Vue劫持data

作者: JX灬君 | 来源:发表于2021-08-09 01:04 被阅读0次
    • window上生成Vue

    在用Rollup搭建开发环境时,用了format:"umd",的打包模式。
    umd的打包模式会在window上添加Vue节点。
    例如:在src/index.js中

    export default function Vue() {
      console.log('Vue节点');
    }
    

    rollup打完包后在html页面中引入生成的vue.js
    然后打印Vue

    <body>
        <div id="Vue">首页</div>
        <script src="dist/vue.js"></script>
        <script>
            // umd 打包模式会给window添加Vue
            console.log(Vue);
        </script>
    </body>
    

    页面结果为


    image.png
    • 操作

    1. 在页面配置Vue
    new Vue({
        el: '#app', // el 挂载元素的位置,也叫编译模版
        data: {
        }
    })
    
    1. 在js里拿到用户的配置项
    export default function Vue(options) {
      console.log(options); // options为用户配置项
    }
    
    1. 设置初始化方法
      新建init.js
    export function initMixin(Vue) {
      Vue.prototype._init = function (options) {  
        console.log(options);
      }
    }
    

    在index.js中注入调用

    import { initMixin } from "./init";
    
    function Vue(options) {
      // 初始化
      this._init (options) // _init 初始化方法 使用前先放到Vue原型链上
    }
    // 初始化,在init.js文件中给Vue原型链添加_init初始化方法
    initMixin(Vue)
    
    export default Vue
    

    初始化状态
    新建initState.js

    import { initData } from "./initData";
    
    export function initState(vm) {  
      let ops = vm.$options // 获取用户配置项
      console.log(ops);
      // 判断
      if (ops.data) {
        initData(vm) // data初始化
      }
    }
    

    初始化data
    新建initData.js

    export function initData(vm) {
      let data = vm.$options.data
      data = typeof data === "function"?data.call(vm):data; // 注意 通过call指向vue的实例
      // 对数据进行劫持
      
    } 
    

    劫持data

    import { observe } from "./observe/index";
    export function initData(vm) {
      let data = vm.$options.data
      
      // 在vm上添加一个属性 _data
      data = vm._data =  typeof data === "function"?data.call(vm):data; // 注意 通过call指向vue的实例
      // 对数据进行劫持
      // data 有两种类型对象和数组 {a:{b:1}, list:[]}
      observe(data)
    
    } 
    

    判断data是对象还是数组,然后通过创建一个类来劫持对象data

    • 劫持对象
    1. 劫持对象用Object.defineProerty,有个缺点,只能对对象中对一个属性进行劫持
    2. 遍历data进行劫持
    3. 嵌套对data 用递归 进行深度劫持
    export function observe(data) {
      console.log(data);
      // 1.判断类型是否是对象
      if (typeof data != 'object' || data == null) {
        return data;
      }
      // 1. 对象,通过一个类来劫持对象data
      return new Observer(data) 
    }
    
    // 用来劫持对象的类
    class Observer{
      constructor (value){ // constructor 数据观测
        this.walk(value) // 遍历
      }
      walk(data){
        let keys = Object.keys(data) // 获取对象
        for (let i = 0; i < keys.length; i++) {
          // 在这个循环里对每个属性进行劫持
          let key = keys[i];  // 属性
          let value = data[key] // 值
          defineReactive(data, key, value)
        }
      }
    }
    
    function defineReactive(data, key, value) { //{a:{b:1}}
      observe(value) // 深度代理,深度劫持
      // 对对象中对属性进行劫持
      Object.defineProperty(data,key,{
        get(){ // 使用获取
          console.log('获取时触发');
          return value
        },
        set(newValue){ // 修改的时候
          console.log('设置时触发');
          if(newValue == value) return ;
          value = newValue
        }
      })
    }
    
    // {}
    
    • 劫持数组
      方法:函数劫持,重写数组方法,也就是劫持数组方法
    // 重写数组
    // 1. 获取原来的数组方法
    let oldArrayProtoMethods = Array.prototype
    // 2. 继承
    export let ArrayMethods = Object.create(oldArrayProtoMethods) // 创建一个对象
    // 劫持
    let methods = [
      "push",
      "pop",
      "unshift",
      "shift",
      "splice"
    ]
    methods.forEach(item => {
      ArrayMethods[item] = function (...args) {  
        console.log('劫持数组');
        let result = oldArrayProtoMethods[item].apply(this, args) // this执行当前的数组 {list: []}
        return result
      }
    })
    

    相关文章

      网友评论

        本文标题:Vue劫持data

        本文链接:https://www.haomeiwen.com/subject/lokwvltx.html