v-for的简单实现

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
    li{
        height:30px;
        line-height:30px
    }
    li:not([data-key]){
        color:red;
        font-size:16px
    }
</style>
</head>
<body>
    <div id="example-1">
        <div>这是一个v-for的示范</div>
        <div>
            <ul>
                <li>第一个v-for</li>
                <li v-for="(item,index) in list" :key="id">
                  {{ item.message }}
                </li>
                <li>第二个v-for</li>
                <li v-for="(student,no) in students" :key="no">
                  {{ student.name }}
                </li>
                <li>下面是数组v-for</li>
                <li v-for="(n,m) in arr" :key="m">
                  {{ n }}
                </li>
            </ul>
        </div>
    </div>
</body>
</html>
<script>
    class Vue{
        constructor(obj){
            this.mountEl = document.querySelector(obj.el);
            this.data = obj.data;
            this.hasChild(this.mountEl);
        }
        hasChild(el){
            if(el.children){
           //        类数组转为数组四种方法
                //        Array.prototype.call(arr)
                //        [].slice.call(arr)
                //        Array.from(arr)
                //        [...arr].forEach(item=>{
                //            console.log(item)
                //        })
                   let nodeList = mountEl.children;
                [...el.children].forEach(el=>{
                //在这里处理v-for
                    let vF_val = el.getAttribute('v-for');
                    if(vF_val){
                      //v-for的dataList
                          let todoList = null;
                      // key绑定的名称  id
                          let keyName = el.getAttribute('v-bind:key') || el.getAttribute(':key');
                      //li标签内部的大胡子括号中的 item.message
                          let textName = el.innerText.replace('{{','').replace('}}','').trim();
                        let regex="\((.+?)\)";
                      //匹配小括号中的内容,不包括小括号 ,结果为item,index
                          let item_index = vF_val.match(regex)[1];//item,index
                          let item = item_index.split(',')[0]// item
                          let index = item_index.split(',')[1]// index
                          let num = vF_val.lastIndexOf('in');
                        let datListName = vF_val.substr(num+2).trim();//list
                           for(let i in this.data){
                          if(i == datListName){
                              todoList = this.data[i]
                          }
                        }
                        const fragment = document.createDocumentFragment();
                       for(let i = 0;i<todoList.length;i++){
                          let tab = null;
                          if(todoList[i] instanceof Array){
                              tab = false
                          }else if(todoList[i] instanceof Object){
                              tab = true
                          }
                          let todoItem = todoList[i]
                          let li = document.createElement(el.tagName)
                          if(!tab){
                              li.dataset.key = i;
                              li.innerText = todoItem;
                              fragment.appendChild(li);
                          }else{
                              li.dataset.key = todoItem[keyName]
                              if(textName.split('.')[0] === item){// v-for的item和item.message相同变量名
                                       let k = textName.split('.')[1] //message
                                       li.innerText = todoItem[k];
                                  fragment.appendChild(li);
                              }
                          }
                      }
                      el.parentNode.replaceChild(fragment,el)
                    }
                    if(el.children){//递归查询元素
                        this.hasChild(el)
                    }
                })
            }
        }
    }
    var example1 = new Vue({
      el: '#example-1',
      data:{
          msg:1,
        list: [
          { message: 'Foo' ,id:'0'},
          { message: 'Bar' ,id:'1'},
          { message: 'Ace' ,id:'2'},
          { message: 'Mvp' ,id:'3'},
        ],
        students: [
          { name: '李雷雷' ,no:'0'},
          { name: '韩梅梅' ,no:'1'},
          { name: 'poly' ,no:'2'},
        ],
        arr:[11111,222222,333333]
      }
    })
</script>

运行结果如下:

总结:真正的vue是会处理得到虚拟dom再去render生成dom的,并且实例中维护的数据都是具有setter,getter属性以及watch监察者的,以此达到响应式,这里只是简单的模拟实现一下。

原文地址:https://www.cnblogs.com/hjj2ldq/p/9530862.html