防Vue系列-11 为防Vue系列-07添加响应式代码

这里为07中添加了响应式deepProperty函数

     // ==========================响应式函数deepProperty===================================
      // 要拦截的数组方法
      let arrs = [
        "push",
        "pop",
        "shift",
        "unshift",
        "reserve",
        "splice",
        "sort",
      ];
      // 获取数组对象
      let arrays = Object.create(Array.prototype);
      // 在原型数组中添加拦截器
      arrs.forEach((element) => {
        //做一层proxy处理
        arrays[element] = function (...args) {
          //在这里对数据进行响应式化
          // for (let index = 0; index < arguments.length; index++) {
          // 不是对象,是字符,或数字???
          // console.log(arguments[index], 122);
          deepProperty.call(this, args);
          // }
          //返回响应Array原型
          return Array.prototype[element].apply(this, args);
        };
      });

      // 对象遍历
      function deepProperty(o) {
        let keys = Object.keys(o);
        for (let index = 0; index < keys.length; index++) {
          let key = keys[index];
          let val = o[key];
          if (Array.isArray(val)) {
            // ======数值响应式start======
            val.__proto__ = arrays;
            // ======数值响应式end======
            for (let j = 0; j < val.length; j++) {
              deepProperty.call(this, val[j]);
            }
          } else {
            deepCreateProperty.call(this, o, key, val, true);
          }
        }
      }

      /**
       *@params target:any
       *@params key:String
       *@params val:null
       *@params enumerable:boolean
       */
      //将数据转换成响应式
      function deepCreateProperty(target, key, val, enumerable) {
        // 判断val 是否是对象
        if (typeof val === "object" && val !== null && !Array.isArray(val)) {
          // 是对象就递归
          deepProperty(val);
        }

        Object.defineProperty(target, key, {
          enumerable: !!enumerable, //默认不传参  undefinde false
          get: () => {
            console.log("得到val");
            return val;
          },
          set: (newVal) => {
            if (val === newVal) return;
            this.mountComponet();
            console.log("改变val");
            val = newVal;
          },
        });
      }

      // ==========================combine函数 合并数据与带有{{}}虚拟的Domdom===================================
      //解析data.xxx.xx
      /**
       *@params obj:Object  data:{nama:{firstName:'小',lastName:'陈'}}
       *@params path:String 'xxx.xxx'
       *@return res:any
       */
      function getValueByPath(data, path) {
        let paths = path.split(".");
        //[name, firstName];
        let res = data;
        //循环查找
        for (let index = 0; index < paths.length; index++) {
          res = res[paths[index]];
        }
        // res === '小'
        return res;
      }
      //正则,用来匹配{{}}
      let r = /\{\{(.+?)\}\}/g;
      // 带坑的vnode和数据 合并 生成带数据vnode
      /**
       *@params vnode:VNode (带有{{}}的虚拟dom)
       *@params data:Object(数据源)
       *@return _vnode:VNode(带有数据的虚拟dom)
       */

      function combine(vnode, data) {
        let {
          tag: _tag,
          data: _data,
          value: _value,
          type: _type,
          children: _children,
        } = vnode;
        let _vnode = null;
        if (_type === 3) {
          //文本节点 判断 是否有{{}}
          _value = _value.replace(r, (_, g) => {
            let key = g.trim();
            let value = getValueByPath(data, key);
            return value;
          });
          _vnode = new VNode(_tag, _data, _value, _type);
        } else if (_type === 1) {
          _vnode = new VNode(_tag, _data, _value, _type);
          _children.forEach((element) => {
            _vnode.appendChild(combine(element, data));
          });
        }
        return _vnode;
      }
      /*



// ==========================paraseVnode函数 虚拟dom转真实dom===================================
 *@params tag:String  'div||span||h1'
 *@params data:Object '{id:'root,class:'theme'...}'
 *@params value:String 'nodeValue || undefined'
 *@params type:Number 'nodeType=1 || 2 ||3 '
 *@params children:Array<Vnode> 
 @return dom:HtmlElement 
 */
      function createElement(tag, data, value, type, children) {
        let dom; //定义储存dom变量
        // 元素节点
        if (type === 1) {
          //创建元素
          dom = document.createElement(tag);
          //添加属性
          for (const key in data) {
            if (data.hasOwnProperty.call(data, key)) {
              dom.setAttribute(key, data[key]);
            }
          }
          // 存在子节点遍历循环递归
          if (children) {
            for (let index = 0; index < children.length; index++) {
              let nodeTag = children[index].tag;
              let nodeData = children[index].data;
              let nodeValue = children[index].value;
              let nodeType = children[index].type;
              let nodeChildren = children[index].children;
              dom.appendChild(
                createElement(
                  nodeTag,
                  nodeData,
                  nodeValue,
                  nodeType,
                  nodeChildren
                )
              );
            }
          }
        }
        // 文本节点,创建文本节点
        else if (type === 3) {
          dom = document.createTextNode(value);
        }
        return dom;
      }

      /*
 *@params vnode:Object
 @return dom:HtmlElement 
 */
      function paraseVnode(vnode) {
        return createElement(
          vnode.tag,
          vnode.data,
          vnode.value,
          vnode.type,
          vnode.children
        );
      }

      // ==========================getVNode函数 真实dom转虚拟dom===================================
      /*
       *@params tag:String  'div||span||h1'
       *@params data:Object '{id:'root,class:'theme'...}'
       *@params value:String 'nodeValue || undefined'
       *@params type:Number 'nodeType=1 || 2 ||3 '
       */
      class VNode {
        constructor(tag, data, value, type) {
          this.tag = tag && tag.toLocaleLowerCase();
          this.data = data;
          this.value = value;
          this.type = type;
          this.children = []; //子节点数组,默认[]
        }
        // 添加子节点
        appendChild(childrenNode) {
          this.children.push(childrenNode);
        }
      }
      /*
       *@params realDom:HtmlElement  '真实的DOM对象'
       *@return vNode:Object '虚拟的DOM对象'
       */
      function getVNode(realDom) {
        let nodeType = realDom.nodeType; //节点类型
        let _vode = null;
        // 元素节点
        if (nodeType === 1) {
          let tag = realDom.nodeName; //标签名
          let attributes = realDom.attributes; //对象属性
          let childNodes = realDom.childNodes; //子节点
          // 获取属性对象
          let data = {};
          for (let i = 0; i < attributes.length; i++) {
            let key = attributes[i].nodeName;
            let value = attributes[i].value;
            data[key] = value;
          }
          // 生成虚拟dom对象
          _vode = new VNode(tag, data, undefined, nodeType);
          //如果有子节点,添加子节点,递归遍历  ===本节难点!!!===
          for (let i = 0; i < childNodes.length; i++) {
            _vode.appendChild(getVNode(childNodes[i]));
          }
        }
        // 文本节点
        else if (nodeType === 3) {
          _vode = new VNode(undefined, undefined, realDom.nodeValue, nodeType);
        }
        return _vode; //虚拟dom
      }

      // ==========================Vue构造函数===================================
      function Vue(options) {
        // 内部数据使用_ 开头 ,只读数据$开头
        this._data = options.data;
        this._el = options.el;
        //准备工作(模板)
        this.$el = this._templateNode = document.querySelector(this._el); //获取挂载的对象
        this._parent = this._templateNode.parentNode; //父节点

        //将数据全部转成响应式的
        deepProperty.call(this, this._data);
        //挂载
        this.mount();
      }
      //挂载
      Vue.prototype.mount = function () {
        this.render = this.createRenderFn(); //生成带有data数据的vnode
        //挂载dom
        this.mountComponet();
      };
      // 函数颗粒化,缓存带有{{}}的vnode
      Vue.prototype.createRenderFn = function () {
        //带坑的虚拟dom
        let ast = getVNode(this.$el);
        return function () {
          // 生成带数据vnode
          let combineData = combine(ast, this._data);
          return combineData;
        };
      };
      //这里就是以后当数据发生变化watcher来进行调用  更新组件vue diff算法就在这里
      Vue.prototype.mountComponet = function () {
        this.updata(this.render());
      };
      // 更新dom 到页面
      Vue.prototype.updata = function (vnode) {
        //将带有数据的vnode转成真实的dom
        let realDom = paraseVnode(vnode);
        //这里我们直接操作dom替换了,后面再细讨论
        this._parent.replaceChild(realDom, document.querySelector("#root"));
      };
      // 创建Vue的实例
      const vm = new Vue({
        el: "#root",
        data: {
          age: 1,
          name: {
            firstName: "小",
            lastName: "陈",
          },
          date: [1, 2, 3, 4],
        },
      });

总结这里还是有点瑕疵,数组中的1,2,3,4不能响应式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Vue.js是一种JavaScript框架,用于构建用户界面。它具有简单易用的语法和强大的响应式能力。Vue官网提供了一个响应式官网的模板,使开发者可以非常方便地创建自己的官网。 这个模板提供了一个完整的官网结构,包括主页、文档、示例、社区等模块。主页展示了Vue的特点和优势,吸引开发者的关注。文档模块详细介绍了Vue的使用方法和API文档,让开发者能够迅速上手并深入学习Vue的各种功能。示例模块展示了一些实际的应用场景,帮助开发者理解Vue的实际使用方式。社区模块提供了一个交流平台,开发者可以在这里提问、分享和讨论问题。 这个模板使用了Vue的核心概念——响应式数据。开发者只需在模板中编写数据和模板的绑定关系,在数据发生变化时,模板会自动根据新的数据重新渲染,达到响应式的效果。这样的设计使得开发者可以专注于数据的处理,而不需要手动操作DOM。 除了响应式数据,模板还支持组件化开发。开发者可以通过编写组件来实现模块的复用和可维护性。Vue的组件系统具有灵活的组件通信和组件复用方式,可以帮助开发者更好地组织和管理代码。 总之,Vue响应式官网模板是一个强大而实用的工具,使得开发者可以方便地构建自己的官网,并享受到Vue带来的响应式和组件化开发的优势。无论是新手还是有经验的开发者,都能从这个模板中获得很多帮助和启发。 ### 回答2: Vue.js是一种用于构建用户界面的渐进式JavaScript框架。官网模板是Vue.js官方提供的用于创建响应式网站的标准模板。这个模板包含了一些常见的网站页面组件,如导航栏、侧边栏、内容区域等,开发者可以根据自己的需求进行定制和修改。 官网模板使用Vue响应式原理,通过数据绑定的方式实现视图和数据的实时同步更新。当数据发生改变时,模板中绑定的相应视图也会被更新。这种方式使得开发者可以更加方便地管理和修改数据,提高了开发效率。 官网模板还提供了一些常用的功能组件,如轮播图、滚动导航等,这些组件已经构建好,只需要根据自己的需求添加和修改相关内容即可。另外,官网模板也提供了一些常用的UI样式,如按钮、表格等,这些样式可以帮助开发者快速构建出具有统一风格的网站页面。 除了基本的页面组件和功能组件外,官网模板还提供了一些常用的路由和状态管理功能,这使得开发者能够更好地管理网站的导航和页面状态。同时,官网模板还支持国际化功能,可以根据用户的语言环境自动切换显示内容,提高了网站的可用性。 总而言之,Vue.js响应式官网模板是一种方便快捷的开发工具,它提供了大量的页面组件、功能组件和样式,支持路由和状态管理,并具有响应式的特性,使得开发者能够更加轻松地创建出现代化的响应式网站。 ### 回答3: Vue.js是一个用于构建用户界面的渐进式JavaScript框架。它提供了一种响应式的数据绑定机制,使得在数据发生变化时,视图可以实时更新。官网模板是Vue.js官方提供的一个示例模板,展示了Vue.js的一些核心概念和用法。 官网模板主要包含了几个重要的部分: 1. 导航栏:位于页面的顶部,提供了一些常用链接,如文档、教程、示例等。导航栏的内容可以根据需要进行修改和扩展。 2. 主体内容:官网模板的主要部分,展示了Vue.js的一些核心概念和用法,以及相关的示例代码和解释。主体内容部分可以根据具体需求进行修改和定制。 3. 侧边栏:位于页面的左侧,提供了一些额外的导航链接,如API文档、生态系统等。侧边栏的内容也可以根据需要进行修改和扩展。 官网模板的设计风格简洁清晰,能够直观地展示Vue.js的特点和优势。通过阅读官网模板,开发者可以快速了解Vue.js的基本概念,学习其使用方法,并在实际开发中运用到自己的项目中。 总之,Vue.js官网模板是一个很好的学习和参考资源,能够帮助开发者快速入门Vue.js,并提供了丰富的示例代码和解释,使开发者能够更好地理解和运用Vue.js响应式机制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值