解析vue的v-text,v-for,v-show,v-html,v-model,{{}},v-if,v-else语法的简单实现方法,支持ie8使用

注意:未经允许不可私自转载,违者必究

本篇文章的技术是模仿vue常用指令加以改编。本人菜鸟一枚,希望有志同道合的同学完善本方法,本方法经过简单测试可以用在juqery,layui等框架里面,本方法支持ie8和ie8以上浏览器。

指令用法

<div id="app">
        <div>1.v-text指令</div>
        <div v-text="{{aaa.aa.a}}"></div>
        <br />
        <div>2.{{指令</div>
        <div>{{aaa.b}} 啊啊啊啊啊{{aaa.a}}</div>
        <br />
        <div>3.输入框双向绑定</div>
        <div>{{aaa.a}}</div>
        <br />
        <input type="text" value="{{aaa.a}}">
        <input type="text" value="{{aaa.b}}">
        <br />
        <br />
        <div>4.v-html指令</div>
        <div v-html="{{html}}"></div>
        <div>4.列表循环</div>
        <div v-for="{{list:(item,index)}}" class="list" v-if="{{index == 0}}">
            <div style="color:#f00">{{item.a}}吼吼吼{{index}}</div>
            
        </div>
        <br />
        <div>5.v-show指令</div>
        <div v-show="{{aaa.b}}">可以看见我了{{aaa.b}}</div>
        <div v-show="{{!aaa.b}}">真正的我隐藏了</div>
        <br />
        <div>6. :指令</div>
        <div :style="{{'color:'+color}}">我是红色的</div>
        <div>7. 加减乘除</div>
        <div>{{1 + (2 / 5)}}</div>
        <div>8. v-if指令</div>
        <div v-if="{{aaa.b == 2222}}" :style="{{'color:'+color}}">可以看见我了{{aaa.b}}</div>
        <div v-else-if="{{aaa.a == 'aaa'}}">可以看见我了</div>
        <div v-else>我是最后的</div>
    </div>

js用法

var insert = new dataDom("app", {
            aaa: {
                a: 111,
                b: 2222,
                aa: {
                    a: 222
                },
            },
            list: [{
                a: 1,
                // list: [1, 2, 3, 4]
            }, {
                a: 2,
                // list: [1, 2, 3, 4]
            }],
            html: "<a href='http://www.baidu.com'>百度</a>",
            color: "#F00"
        });
        setTimeout(function () {
            insert.setData({
                aaa: {
                    a: "aaa",
                    aa: {
                        a: "a11a1"
                    },
                },
            });
        }, 2000);
        setTimeout(function () {
            insert.setData({
                aaa: {
                    a: "啊啊啊",
                    b: 2222,
                    aa: {
                        a: "啊啊啊"
                    }
                },
                list: [{
                    a: "啊",
                    list: [1, 2, 3, 4]
                }, {
                    a: "哦",
                    list: [1, 2, 3, 4]
                }],
                color: "#0f0"
            });
        }, 6000);

下面是dataDom方法源码(323行)

//去收尾空格
function trim(str) {
    return str.replace(/^(\s|\xA0)+|(\s|\xA0)+$/g, '');
}
function getNextElement(node) {
    var value = null;
    siblingRecursive(node);
    function siblingRecursive(node) {
        var NextElementNode = node.nextSibling;
        if (NextElementNode && NextElementNode.nodeType == 3) {
            siblingRecursive(NextElementNode);
        } else {
            value = NextElementNode;
        }
    }
    return value;
}
var syncProcessSign = false;
//{{}}里方法获取数据值
function jsMatch(text, data, callback) {
    if (text && trim(text)) {
        var reg = /\{\{(.*?)\}\}/g;
        var backString = false;
        if (text.replace(reg, "")) {
            backString = true;
        };
        var textList = text.match(reg);
        //条件列表
        var conditionList = [];
        //js方法列表
        var jsList = [];
        if (textList) {
            var textLen = textList.length;
            for (var t = 0; t < textLen; t++) {
                var arrtext = textList[t].substring(2, textList[t].length - 2);
                conditionList.push(arrtext);
                for (var key in data) {
                    var keyReg = new RegExp(key, "g");
                    var matchList = arrtext.match(keyReg);
                    if (matchList) {
                        for (var m = 0; m < matchList.length; m++) {
                            var x = arrtext.indexOf(matchList[m]);
                            for (var w = 1; w < m + 1; w++) {
                                x = arrtext.indexOf(matchList[m], x + 1);
                            };
                            if (x == 0) {
                                arrtext = "data." + arrtext;
                            } else {
                                var value1 = arrtext.substring(x - 1, x);
                                if (value1 != "." && value1 != "'" && value1 != '"' && value1 != ':') {
                                    arrtext = arrtext.substring(0, x) + "data." + arrtext.substring(x);
                                };
                            };
                        }
                    }
                }
                try {
                    jsList.push(arrtext);
                    var dataVal = eval(arrtext);
                    if (!backString && textLen <= 1) {
                        text = dataVal;
                    } else {
                        text = text.replace(textList[t], dataVal)
                    }
                } catch (err) {
                    // console.log(err);
                    text = false;
                }
            }
            callback && callback(text, conditionList, jsList);
        } else {
            callback && callback(false, conditionList, jsList);
        }
    } else {
        callback && callback(false, [], []);
    }
}

function dataDom(el, data) {
    var $el = document.getElementById(el);
    //页面数据替换节点集合
    var domList = [];
    //待操作dom元素的方法集合
    var waitWithList = [];
    var _this = this;
    //页面数据更新
    this.render = function (options, attrValue) {
        var len = domList.length;
        for (var index = 0; index < len; index++) {
            var domItem = domList[index];
            if (options && domItem.make == "v-for") {
                jsMatch(domItem.initValue, options, function (showValue){
                    if (showValue) {
                        waitWithList = [];
                        var forDomList = [];
                        var listLen = showValue.length;
                        var childData = {};
                        for (var dataKey in data) {
                            childData[dataKey] = data[dataKey];
                        };
                        for (var itemIndex = 0; itemIndex < listLen; itemIndex++){
                            childData[domItem.forConfig.item] = showValue[itemIndex];
                            childData[domItem.forConfig.index] = itemIndex;
                            var newNode = domItem.node.cloneNode(true);
                            newNode.removeAttribute("v-for");
                            attrData(newNode, childData, false, function (newNode, newIsChildlen) {
                                if (newIsChildlen) {
                                    var dom = domReplace(newNode, childData, false);
                                    forDomList.push(dom);
                                    if (domItem.getNextSibling) {
                                        domItem.parent.insertBefore(dom, domItem.getNextSibling);
                                    } else {
                                        domItem.parent.appendChild(dom);
                                    }
                                }
                            });
                        }
                        for (var r = 0; r < domItem.removeList.length; r++) {
                            domItem.parent.removeChild(domItem.removeList[r]);
                        }
                        domItem.removeList = forDomList;
                        //处理元素
                        if (waitWithList.length > 0) {
                            for (var a = 0; a < waitWithList.length; a++) {
                                var item = waitWithList[a];
                                if (item.value1) {
                                    item.aims[item.type](item.value, item.value1);
                                } else {
                                    item.aims[item.type](item.value);
                                }
                            }
                        }
                    }
                });
            } else if (domItem.make == "v-show") {
                jsMatch(domItem.initValue, data, function (showValue) {
                    if (domItem.oldValue !== showValue) {
                        if (showValue) {
                            domItem.node.style.display = "inherit";
                        } else {
                            domItem.node.style.display = "none";
                        }
                        domItem.oldValue = showValue;
                    }
                });
            } else if (domItem.make == "v-if") {
                var newTrueNode = "";
                if (domItem.trueNode) {
                    try {
                        domItem.parent.removeChild(domItem.trueNode);
                    } catch (error) {
                        console.log(error);
                    }
                }
                var ifListLen = domItem.ifNodeList.length;
                ifRecursive(0);
                function ifRecursive(index) {
                    var ifNode = domItem.ifNodeList[index];
                    // console.log(ifNode);
                    if (ifNode.ifInst == "v-else") {
                        attrData(ifNode.node, data, false, function (newNode, newIsChildlen) {
                            newTrueNode = newNode;
                            if (domItem.getNextSibling) {
                                domItem.parent.insertBefore(newNode, domItem.getNextSibling);
                            } else {
                                domItem.parent.appendChild(newNode);
                            }
                        });
                    } else {
                        jsMatch(ifNode.ifInst, data, function (showValue) {
                            if (showValue) {
                                attrData(ifNode.node, data, false, function (newNode, newIsChildlen) {
                                    newTrueNode = newNode;
                                    if (domItem.getNextSibling) {
                                        domItem.parent.insertBefore(newNode, domItem.getNextSibling);
                                    } else {
                                        domItem.parent.appendChild(newNode);
                                    }
                                });
                            } else if (index < ifListLen - 1){
                                ifRecursive(index + 1);
                            }
                        });
                    }
                }
                domItem.trueNode = newTrueNode;
            } else {
                jsMatch(domItem.initValue, data, function (showValue) {
                    if (showValue && domItem.oldValue != showValue) {
                        if (domItem.type == "setAttribute") {
                            domItem.node.setAttribute(domItem.make, showValue);
                            domItem.oldValue = showValue;
                        } else if (attrValue && domItem.node.nodeName == "INPUT") {

                        } else {
                            domItem.node[domItem.type] = showValue;
                            domItem.oldValue = showValue;
                        }
                    }
                });
            }
        }
    }
    function attrData(node, data, store, callback, type) {
        var isChildlen = true;
        if (node.hasAttribute("v-for")) {
            var forConfig = {
                item: "item",
                index: "index",
            };
            var attrValue = node.getAttribute("v-for");
            //获取for循环的数据名称和索引名称
            attrValue = attrValue.replace(/\:\((.*?)\,(.*?)\)/g, "");
            forConfig.item = RegExp.$1;
            forConfig.index = RegExp.$2;
            jsMatch(attrValue, data, function (text, conditionList, jsList) {
                if (text) {
                    isChildlen = false;
                    var getNextSibling = getNextElement(node);
                    var getParentNode = node.parentNode;
                    var listLen = text.length;
                    var childData = {};
                    var forDomList = new Array;
                    for (var dataKey in data) {
                        childData[dataKey] = data[dataKey];
                    }
                    for (var itemIndex = 0; itemIndex < listLen; itemIndex++) {
                        childData[forConfig.item] = text[itemIndex];
                        childData[forConfig.index] = itemIndex;
                        var newNode = node.cloneNode(true);
                        newNode.removeAttribute("v-for");
                        attrData(newNode, childData, false, function (newNode, newIsChildlen) {
                            if (newIsChildlen) {
                                var dom = domReplace(newNode, childData, false);
                                forDomList.push(dom);
                                if (getNextSibling) {
                                    waitWithList.push({
                                        aims: getParentNode,
                                        type: "insertBefore",
                                        value: dom,
                                        value1: getNextSibling,
                                    });
                                } else {
                                    waitWithList.push({
                                        aims: getParentNode,
                                        type: "appendChild",
                                        value: dom,
                                    });
                                }
                            }
                        });

                    }
                    domList.push({
                        node: node,
                        make: "v-for",
                        initValue: attrValue,
                        oldValue: text,
                        removeList: forDomList,
                        getNextSibling: getNextSibling,
                        type: "v-for",
                        parent: getParentNode,
                        forConfig: forConfig,
                    });
                    waitWithList.push({
                        aims: getParentNode,
                        type: "removeChild",
                        value: node
                    });
                }
            });
        } else if (node.hasAttribute("v-else") || node.hasAttribute("v-else-if")) {
            isChildlen = false;
        } else if (node.hasAttribute("v-if")) {
            var attrValue = node.getAttribute("v-if");
            node.removeAttribute("v-if");
            var ifNodeList = new Array;
            var getParentNode = node.parentNode;
            var lastNewIsChildlen = "";
            var trueNode = "";
            recursive(attrValue, node, false);
            function recursive(val, node, result) {
                ifNodeList.push({
                    node: node,
                    ifInst: val,
                    value: result
                });
                if (val == "v-else") {
                    if (result) {
                        if (getParentNode) {
                            waitWithList.push({
                                aims: getParentNode,
                                type: "removeChild",
                                value: node
                            });
                        }
                    } else {
                        attrData(node, data, store, function (newNode, newIsChildlen) {
                            trueNode = newNode;
                            isChildlen = newIsChildlen;
                        });
                    }
                } else {
                    var nextSibling = getNextElement(node);
                    var nextValue = false;
                    if (nextSibling) {
                        if (nextSibling.hasAttribute("v-else-if")) {
                            nextValue = nextSibling.getAttribute("v-else-if");
                            nextSibling.removeAttribute("v-else-if");
                        } else if (nextSibling.hasAttribute("v-else")) {
                            nextSibling.removeAttribute("v-else");
                            nextValue = "v-else";
                        } else {
                            var lastChildlen = getNextElement(nextSibling);
                            lastNewIsChildlen = lastChildlen ? lastChildlen : "";
                        }
                    }
                    if (result) {
                        if (getParentNode) {
                            waitWithList.push({
                                aims: getParentNode,
                                type: "removeChild",
                                value: node
                            });
                        }
                        if (nextValue) {
                            recursive(nextValue, nextSibling, true);
                        }
                    } else {
                        jsMatch(val, data, function (text, conditionList, jsList) {
                            if (text) {
                                attrData(node, data, store, function (newNode, newIsChildlen) {
                                    trueNode = newNode;
                                    isChildlen = newIsChildlen;
                                });
                                if (nextValue) {
                                    recursive(nextValue, nextSibling, true);
                                }
                            } else {
                                if (getParentNode) {
                                    waitWithList.push({
                                        aims: getParentNode,
                                        type: "removeChild",
                                        value: node
                                    });
                                }
                                if (nextValue) {
                                    recursive(nextValue, nextSibling, false);
                                }
                            }
                        });
                    }
                }
            };
            if (!trueNode) {
                isChildlen = false;
            }
            if (getParentNode && store) {
                var domConfig = {
                    node: node,
                    make: "v-if",
                    getNextSibling: lastNewIsChildlen,
                    parent: getParentNode,
                    ifNodeList: ifNodeList,
                    trueNode: trueNode
                }
                domList.push(domConfig);
            }
        } else {
            //标签节点数据处理
            var nodeAttr = node.attributes;
            var attrLen = nodeAttr.length;
            //循环单一标签所有属性
            for (var j = 0; j < attrLen; j++) {
                var attr = nodeAttr[j];
                var name = attr.name;
                var attrValue = attr.value;
                //ie8不支持style="{{}}"会识别为语法错误,ie8需要用:style
                if (name == ":style") {
                    name = "style";
                }
                //判断属性值是否有{{}},如果有并返回值
                jsMatch(attrValue, data, function (text, conditionList, jsList) {
                    var domConfig = {
                        node: node,
                        make: name,
                        initValue: attrValue,
                        oldValue: text
                    };
                    var isRemove = false;
                    if (name == 'v-show') {
                        if (text) {
                            node.style.display = "inherit";
                        } else {
                            node.style.display = "none";
                        };
                        domConfig.type = "style";
                        isRemove = true;
                    } else if (text) { //返回的值是true才执行下面代码
                        if (node.nodeName == "INPUT" || node.nodeName == "TEXTAREA") {
                            node.value = text;
                            domConfig.type = "value";
                            getinput(node, jsList[0]);
                            //input输入框数据绑定
                            function getinput(node, jsNode, attrValue) {
                                //判断浏览器是否支持addEventListener
                                if (node.addEventListener) {
                                    node.addEventListener('input', function (e) {
                                        var newVal = e.target.value;
                                        eval(jsNode + "='" + newVal + "'");
                                        _this.render();
                                    });
                                } else {
                                    node.onpropertychange = function (e) {
                                        if (syncProcessSign) {
                                            return;
                                        }
                                        syncProcessSign = true;
                                        var newVal = node.value;
                                        eval(jsNode + "='" + newVal + "'");
                                        _this.render("", attrValue);
                                        syncProcessSign = false;
                                    }
                                }
                            }
                            isRemove = true;
                        } else if (name == 'v-text') {
                            domConfig.type = "innerText";
                            node.innerText = text;
                            isRemove = true;
                        } else if (name == 'v-html') {
                            domConfig.type = "innerHTML";
                            node.innerHTML = text;
                            isRemove = true;
                        } else {
                            node.setAttribute(name, text);
                            domConfig.type = "setAttribute";
                        }
                    }
                    if (store) {
                        domList.push(domConfig);
                    }
                    if (isRemove) {
                        waitWithList.push({
                            aims: node,
                            type: "removeAttribute",
                            value: attr.name,
                        });
                    }
                });
            };
        }
        callback && callback(node, isChildlen);
    }
    //数据赋值并更新页面数据
    this.setData = function (options) {
        for (var key in options) {
            data[key] = options[key];
        }
        _this.render(options);
    };
    //首次加载替换节点数据
    domReplace($el, data, true);
    //首次加载处理需要操作的元素方法
    if (waitWithList.length > 0) {
        for (var a = 0; a < waitWithList.length; a++) {
            var item = waitWithList[a];
            if (item.value1) {
                item.aims[item.type](item.value, item.value1);
            } else {
                item.aims[item.type](item.value);
            }
        }
    }
    //获取页面的数据节点集合并向页面添加数据
    function domReplace(frag, data, store) {
        var childNodes = frag.childNodes;
        var childlen = childNodes.length;
        for (var i = 0; i < childlen; i++) {
            var node = childNodes[i];
            
            var txt = node.nodeValue;
            var isChildlen = true;
            var reg = /\{\{(.*?)\}\}/g; // 正则匹配{{}}
            //页面里的script和style的标签不做处理并跳过子元素
            if (node.nodeName == "SCRIPT" || node.nodeName == "STYLE") {
                isChildlen = false;
                return;
            }
            //文本节点{{}}处理
            if (node.nodeType === 3) {
                jsMatch(txt, data, function (text, conditionList, jsList) {
                    if (text) {
                        node.nodeValue = text;
                        if (store) {
                            domList.push({
                                node: node,
                                make: "",
                                type: "nodeValue",
                                oldValue: text,
                                initValue: txt
                            });
                        }
                    }
                });
            } else if (node.nodeType === 1) {
                attrData(node, data, store, function (newNode, newIsChildlen) {
                    isChildlen = newIsChildlen;
                });
            };
            // 如果还有子节点,继续递归replace
            if (isChildlen && node.childNodes && node.childNodes.length) {
                domReplace(node, data, store);
            }
        }
        return frag;
    }
}

本方法就这么多东西

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值