91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Vue2中的數據劫持怎么實現

發布時間:2023-02-23 16:37:01 來源:億速云 閱讀:142 作者:iii 欄目:開發技術

今天小編給大家分享一下Vue2中的數據劫持怎么實現的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

我們今天要編寫的項目通過需要使用 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 文件內容如下:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title></title>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

全部文件目錄結構如圖:

Vue2中的數據劫持怎么實現

首先,我們需要編寫我們的入口文件 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;

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
};

以上代碼,我們通過proxyDatadata中的數據進行攔截,詳情如下:

// 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
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 < keys.length; i++) {
    let key = keys[i];
    let value = data[key];
    // 攔截 data 數據
    // 分別傳入參數為:vm._data、data 中的 key、data 中 key 對應的 value
    defineReactiveData(data, key, value);
  }
};
export default Observer;

以上代碼,我們分別對數組和對象執行不同的操作,我們先來看對象的操作:
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(`???? 響應式設置:data.${key},`, newVal);
      if (newVal === value) {
        return false;
      }
      // 如果新值還是對象,那么接著進行觀察
      observe(newVal);
      value = newVal;
    }
  });
}
export default defineReactiveData;

以上代碼,我們是對vm._data進行攔截的,這是因為我們前面說的proxyData攔截的是vm對象,當訪問vm.title的時候,proxyData的攔截就會生效,而proxyData內部是通過vm._data來獲取的,這樣又會觸發defineReactiveData的攔截!

回到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 {
   // ...
  }
}
Observer.prototype.walk = function (data) {
  // ...
};
export default Observer;

以上代碼我們對數組更改一個原型arrMethods,那看看它到底做了什么事情:

// vue/array.js
// ARR_METHODS 是一些可以更改數組本身的方法,里面包括以下內容,我們就不展開看了
// ["push", "pop", "shift", "unshift", "splic", "sort", "reverse"]
import { ARR_METHODS } from "./config";
import observeArr from "./observeArr";
// 把數組本身的元素進行拷貝
var originArrayMethods = Array.prototype;
// 創建一個空對象,該空對象的原型就是數組的原型
var arrMethods = Object.create(originArrayMethods);
// 遍歷這些數組的方法名稱
ARR_METHODS.forEach(function (m) {
  // 在新對象上重寫數組的方法
  arrMethods[m] = function () {
    // 把數組接到的參數轉換為一個數組
    var args = Array.prototype.slice.call(arguments);
    // 執行數組原本的方法
    var rt = originArrayMethods[m].apply(this, args);
    var newArr;
    switch (m) {
      case "push":
      case "unshift":
        // 例如 arr.push({a: 1})
        // args 就是 [{a: 1}]
        newArr = args;
        break;
      case "splice":
        // 例如 arr.splice(1, 0, {a: 1}, {b: 2})
        // args 就是 [{a: 1}, {b: 2}]
        newArr = args.slice(2);
        break;
      default:
        break;
    }
    // 如果有值那面就調用 observeArr 方法
    // observeArr 方法就是循環數組的每一項,然后讓每一項都調用 Observer 方法進行訂閱
    newArr && observeArr(newArr);
    return rt;
  };
});
export { arrMethods };

以上代碼我們重寫了數組相關的方法,這是因為這些方法被并不能被Object.defineProperty攔截到。

詳細請看:v-for 列表循環

所以我們通過重寫方法的方式,讓數組可以正常的執行方法,同時也能被我們的observeArr方法攔截到,所以數組現在就是這樣多了一層我們寫的原型,但最終它還是繼承于Array構造函數的:

Vue2中的數據劫持怎么實現

而我們的observeArr只是遍歷了數組的每一項,讓每一項都進行了攔截:

// vue/observeArr.js
import observe from "./observe";
function observeArr(arr) {
  for (let i = 0; i < arr.length; i++) {
    // 又回到了起點,進行更新訂閱
    observe(arr[i]);
  }
}
export default observeArr;

然后我們去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);
console.log(vm.title);
console.log(vm.teacher);
console.log(vm.info.a);

Vue2中的數據劫持怎么實現

以上就是“Vue2中的數據劫持怎么實現”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

vue
AI

贵阳市| 铜鼓县| 达日县| 长武县| 龙口市| 蓝山县| 赤城县| 阜康市| 玉树县| 广昌县| 巴林右旗| 萨嘎县| 万载县| 石泉县| 安仁县| 磐石市| 江油市| 余江县| 临潭县| 灯塔市| 湘阴县| 广宗县| 炎陵县| 崇左市| 阿勒泰市| 西青区| 宁陕县| 称多县| 凤庆县| 驻马店市| 乐山市| 漳州市| 衡南县| 威海市| 枣强县| 日土县| 芦溪县| 南投县| 巧家县| 鸡泽县| 宣汉县|