搜索

查看: 3174|回复: 11

[JavaScript] Vue2 中的数据劫持简写示例

[复制链接]
发表于 2023-5-4 11:46:35 | 显示全部楼层 |阅读模式
Editor 2023-5-4 11:46:35 3174 11 看全部
目录
  • package.json 相关依赖
  • Webpack.config.js 配置文件
  • public/index.html 文件内容
  • 全部文件目录结构
  • 实例一个模拟的 Vue 应用
  • vue/index.js 文件主要是负责初始化内容
  • initState方法
  • 核心文件vue/observer.js
  • vue/observer.js文件对数组进行处理
    package.json 相关依赖
    我们今天要编写的项目通过需要使用 Webpack 进行编译,package.json 相关依赖如下:
    {
      "scripts": {
        "dev": "webpack-dev-server",
        "build:": "webpack"
      },
      "devDependencies": {
        "html-webpack-plugin": "^4.5.2",
        "webpack": "^4.46.0",
        "webpack-cli": "^3.3.12",
        "webpack-dev-server": "^3.11.3"
      }
    }

    Webpack.config.js 配置文件
    const path = require("path");
    const HtmlWebpackPlugin = require("html-webpack-plugin");
    module.exports = {
      entry: "./src/index.js",
      output: {
        filename: "bundle.js",
        path: path.resolve(__dirname, "dist")
      },
      devtool: "source-map",
      resolve: {
        // 表示解析模块引入的时候先从当前文件夹寻找模块,再去 node_modules 找模块
        modules: [
          path.resolve(__dirname, ""),
          path.resolve(__dirname, "node_modules")
        ]
      },
      plugins: [
        new HtmlWebpackPlugin({
          template: path.resolve(__dirname, "public/index.html")
        })
      ]
    };

    public/index.html 文件内容

      
       
       
       
       
      
      
       
      


    全部文件目录结构

    20230223083636033.jpg

    Vue2 中的数据劫持简写示例4627 作者:Editor 帖子ID:2694 vue下一页知鸟论坛_zn60.com


    好了,接下来我们就开始发车!

    实例一个模拟的 Vue 应用
    首先,我们需要编写我们的入口文件 index.js,该文件很普通主要就是实例一个模拟的 Vue 应用:
    // index.js
    // 我们在 webpack.config.js 中进行了配置,所以这里优先在当前目录下寻找 vue 文件,也就是我们的 vue/index.js 文件
    import Vue from "vue";
    let vm = new Vue({
      el: "#app",
      data() {
        return {
          title: "学生列表",
          classNum: 1,
          teacher: ["张三", "李四"],
          info: {
            a: {
              b: 1
            }
          },
          students: [
            {
              id: 1,
              name: "小红"
            },
            {
              id: 2,
              name: "小明"
            }
          ]
        };
      }
    });
    console.log(vm);

    vue/index.js 文件主要是负责初始化内容
    // src/sindex.js
    import { initState } from "./init";
    function Vue(options) {
      this._init(options);
    }
    Vue.prototype._init = function (options) {
      // this 指向当前实例对象
      var vm = this;
      // 我们把 new Vue() 时候传递的数据统称为 options
      // 并且挂载到 Vue 的实例对象上
      vm.$options = options;
      // 调用 initState 初始化 data 数据
      initState(vm);
    };
    export default Vue;

    initState方法
    vue/init.js 文件暴露出一个initState方法,该方法主要是处理初始化的数据:
    // vue/init.js
    import proxyData from "./proxy";
    import observer from "./observe"
    function initState(vm) {
      var options = vm.$options;
      // 如果 options 中存在 data 属性,我们才会继续处理
      if (options.data) {
        initData(vm);
      }
    }
    function initData(vm) {
      var data = vm.$options.data;
      // 把 data 数据单独保存到 Vue 的实例化对象上,方便我们获取
      // 如果 data 是一个函数,我们需要执行返回得到返回的对象
      data = vm._data = typeof data === "function" ? data.call(vm) : data || {};
      // 遍历 data 对象,通过 proxyData 对数据进行拦截
      for (const key in data) {
        // 传入的参数分别是:当前实例、key值(也就是 vm._data)、data 中的 key 值(例如 vm._data.title)
        proxyData(vm, "_data", key);
      }
      // 调用观察者模式
      observer(vm._data)
    }
    export {
      initState
    };
    以上代码,我们通过proxyData对data中的数据进行拦截,详情如下:
    // vue/proxy.js
    function proxyData(vm, target, key) {
      // 当访问 vm.title 的时候转换为 vm._data.title
      //(请记住这句话!!!)
      Object.defineProperty(vm, key, {
        get: function () {
          return vm[target][key];
        },
        set: function (newVal) {
          vm[target][key] = newVal;
        }
      });
    }
    export default proxyData;
    我们还调用了observer方法进行事件订阅,详细如下:
    // vue/observe.js
    import Observer from "./observer"
    function observe(data) {
      // 判断只处理对象,如果不是对象直接返回
      if (typeof data !== "object" || data === null) {
        return false;
      }
      // 观察数据
      return new Observer(data)
    }
    export default observe;

    核心文件vue/observer.js
    接下来就是我们的核心文件vue/observer.js,该文件主要负责对数据类型进行判断,如果是数组就需要单独处理数组,这个我们后面再说:
    // vue/observer.js
    import defineReactiveData from "./reactive";
    import { arrMethods } from "./array";
    import observeArr from "./observeArr";
    // 这个方法会在多个地方调用,请记住这个方法以它的作用
    function Observer(data) {
      // 如果 data 是一个数组,那面需要单独处理
      if (Array.isArray(data)) {
        // 给数组新增一层原型
        data._proto__ = arrMethods;
        // 循环数组的每一项,然后让每一项都调用 Observer 方法进行订阅
        observeArr(data)
      } else {
        // 处理对象
        this.walk(data);
      }
    }
    Observer.prototype.walk = function (data) {
      // 获取到 data 全部的 key
      // 也就是我们定义的 ['title', 'classNum', 'teacher', 'info', 'students']
      let keys = Object.keys(data);
      for (var i = 0; i
    以上代码,我们分别对数组和对象执行不同的操作,我们先来看对象的操作:
    在Observer构造函数中我们新增了一个walk方法,该方法获取到了所有的key值,然后调用了defineReactiveData进行处理。
    // vue/reactive.js
    import observe from "./observe";
    function defineReactiveData(data, key, value) {
      // 例如 info.a 还是个对象,那么就递归观察
      observe(value);
      // 这里的 data 是 vm._data,所以这里拦截的也是 vm._data
      Object.defineProperty(data, key, {
        get() {
          console.log(`⤴️ 响应式获取:data.${key},`, value);
          return value;
        },
        set(newVal) {
          console.log(`
  • 20230223083636034.jpg

    Vue2 中的数据劫持简写示例6840 作者:Editor 帖子ID:2694 vue下一页知鸟论坛_zn60.com

    20230223083636035.jpg

    Vue2 中的数据劫持简写示例6143 作者:Editor 帖子ID:2694 vue下一页知鸟论坛_zn60.com
    发表于 2023-6-29 02:42:07 | 显示全部楼层
    塞翁364 2023-6-29 02:42:07 看全部
    楼主,大恩不言谢了!知鸟论坛是最棒的!
    发表于 2023-6-29 15:17:03 | 显示全部楼层
    啤酒瓶空了缓 2023-6-29 15:17:03 看全部
    感谢楼主的无私分享!要想知鸟论坛好 就靠你我他
    发表于 2023-6-29 19:14:18 | 显示全部楼层
    墙和鸡蛋 2023-6-29 19:14:18 看全部
    论坛不能没有像楼主这样的人才啊!我会一直支持知鸟论坛。
    发表于 2023-6-29 20:52:29 | 显示全部楼层
    当当当当裤裆坦 2023-6-29 20:52:29 看全部
    这个帖子不回对不起自己!我想我是一天也不能离开知鸟论坛
    发表于 2023-6-29 21:01:02 | 显示全部楼层
    123456848 2023-6-29 21:01:02 看全部
    感谢楼主的无私分享!要想知鸟论坛好 就靠你我他
    发表于 2023-6-29 21:09:17 | 显示全部楼层
    麻辣鸡翅 2023-6-29 21:09:17 看全部
    楼主太厉害了!楼主,I*老*虎*U!我觉得知鸟论坛真是个好地方!
    发表于 2023-6-29 22:54:57 | 显示全部楼层
    永远爱你冰塘 2023-6-29 22:54:57 看全部
    其实我一直觉得楼主的品味不错!呵呵!知鸟论坛太棒了!
    发表于 2023-6-29 23:01:07 | 显示全部楼层
    李志敏 2023-6-29 23:01:07 看全部
    楼主,大恩不言谢了!知鸟论坛是最棒的!
    发表于 2023-6-30 10:18:56 | 显示全部楼层
    ffycxyw2274436 2023-6-30 10:18:56 看全部
    这东西我收了!谢谢楼主!知鸟论坛真好!
    • 您可能感兴趣
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则 返回列表

    RSS订阅| 小黑屋| 知鸟论坛 |网站地图
    本站资源来自互联网用户收集发布,如有侵权请邮件联系处理。 联系邮箱E-mail:zniao@foxmail.com
    快速回复 返回顶部 返回列表