Vue結合原生js實現自定義元件自動生成

qianby發表於2021-09-09

 就目前三主流資料驅動框架(vue,ng,react)而言,均具有建立自定義元件的api,但都是必須先做到事先寫好掛載點,這個掛載點可以是原有靜態元素標籤也可以是自定義模板;對於多種元件透過同一資料流生成的,如果事先在頁面上寫好掛載點(mounted),然後透過dom操作去動態新增,會遇到類似這樣一條錯誤提示資訊:Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.(…)。這又是為何呢,下一步該怎麼辦?

  原因是任何dom操作的物件必須是符合W3C標準的元素,除非如下所述的,改寫生成html元素物件的原型(HTMLElement.prototype)並註冊自定義元素,從而實現動態生成自定義元件的效果。

  不過,大家都明白使用資料驅動框架的初衷就是儘可能避免dom操作,而如下程式碼中還是有一些dom操作的,就目前認知水平而言,感覺這些必要的dom操作還是避免不了的。其它不多說了,直接看程式碼。。。

`














var jsonData = [
    {
        "keyname": "姓名鄂然失色而熱重重中之重重中之重雜誌的熱熱",
        "type": "text",
        "key": "name11"
    }, {
        "value": "姓名鄂之重雜誌的熱熱",
        "key": "name11"
    }, {
        "keyname": "姓名鄂然失色而熱熱熱熱是重中之重重中之重重中之重雜誌的熱熱",
    },
    {
        "keyname": "姓名鄂然失色而熱熱熱熱是重中之重重中之重重中之重雜誌的熱熱",
        "type": "textarea",
        "key": "name"
    },
    {
        "keyname": "性別",
        "type": "radio",
        "key": "sex",
        "values": [
            {
                "key": "man",
                "value": "男輔導班"
            },
            {
                "key": "women",
                "value": "女"
            }
        ]
    },
    {
        "keyname": "複選",
        "type": "checkbox",
        "key": "checkbox",
        "values": [
            {
                "key": "man",
                "value": "男"
            },
            {
                "key": "women",
                "value": "女"
            }
        ]
    },
    {
        "keyname": "型別",
        "type": "select",
        "key": "type1",
        "values": [
            {
                "key": "type1",
                "value": "型別1"
            },
            {
                "key": "type2",
                "value": "型別2"
            },
            {
                "key": "type3",
                "value": "型別3"
            },
            {
                "key": "type4",
                "value": "型別4"
            }
        ]
    },
    {
        "keyname": "定位",
        "type": "gps",
        "key": "btn",
        "value": "地圖獲取定位"
    },
    {
        "keyname": "拍照",
        "type": "photo",
        "key": "btn",
        "value": "拍照"
    }
];
(function () {
    AnalyJson(jsonData);
})();
function AnalyJson(data) {
    if ('id' in data) {
        arguments.callee(data.values);
    } else {
        if ('name' in data) {
            htmlname = data.name;
            CreateInputViewer(data.name);
            arguments.callee(data.values);
        } else {
            if ('type' in data) {
                CreateInputViewer(data);
            } else {
                for (var p in data) {
                    CreateInputViewer(data[p]);
                }
            }
        }
    }
}
function CreateInputViewer(data) {
    switch (data.type) {
        case 'text': {
            fh_C(data, 'c-input-text' + '-' + data.key, 'fhInputText', textTpl);
            break;
        }
        case 'textarea': {
            fh_C(data, 'c-textarea' + '-' + data.key, 'fhInputTextarea', textareaTpl);
            break;
        }
        case 'radio': {
            fh_C(data, 'c-input-radio' + '-' + data.key, 'fhInputTextarea', radioTpl);
            break;
        }
        case 'checkbox': {
            fh_C(data, 'c-input-checkbox' + '-' + data.key, 'fhInputCheckbox', checkboxTpl);
            break;
        }
        case 'select': {
            fh_C(data, 'c-select' + '-' + data.key, 'fhSelect', selectTpl);
            break;
        }
        case 'photo': {
            fh_C(data, 'c-photo' + '-' + data.key, 'fhPhoto', photoTpl);
            break;
        }
        case 'gps': {
            fh_C(data, 'c-gps' + '-' + data.key, 'fhGPS', gpsTpl);
            break;
        }
        default: {
            fh_C(data, 'c-default' + '-' + data.key, 'fhInputDefault', defaultTpl);
            break;
        }

    }
}
function fh_C(d, c, cn, tpl) {
    console.log(d);
    Vue.component(c, {
        template: tpl,

// props:['key','keyname','values','value'],
data: function () {
return d
}
});
new Vue({
el: '.mui-content',
components: {
cn: cn
},
});
var MyElementProto = Object.create(HTMLElement.prototype);
MyElementProto.createdCallback = function () {
this.innerHTML = tpl
};
var MyComponent = document.registerElement(c, {prototype: MyElementProto});
document.querySelector('.mui-content').appendChild(new MyComponent());
}

`
複製程式碼
為了保持程式碼的可維護性及易讀性,我將模板部分單獨放在fuhao-components.js的檔案裡邊,如下所示:

` var textTpl= '




';
var textareaTpl= '

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/3549/viewspace-2807413/,如需轉載,請註明出處,否則將追究法律責任。

相關文章