最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Vue2?中的數(shù)據(jù)劫持簡(jiǎn)寫(xiě)示例

 更新時(shí)間:2023年02月23日 15:35:42   作者:Serein_  
這篇文章主要為大家介紹了Vue2?中的數(shù)據(jù)劫持簡(jiǎn)寫(xiě)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

package.json 相關(guān)依賴

我們今天要編寫(xiě)的項(xiàng)目通過(guò)需要使用 Webpack 進(jìn)行編譯,package.json 相關(guān)依賴如下:

{
  "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: {
    // 表示解析模塊引入的時(shí)候先從當(dāng)前文件夾尋找模塊,再去 node_modules 找模塊
    modules: [
      path.resolve(__dirname, ""), 
      path.resolve(__dirname, "node_modules")
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "public/index.html")
    })
  ]
};

public/index.html 文件內(nèi)容

<!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>

全部文件目錄結(jié)構(gòu)

好了,接下來(lái)我們就開(kāi)始發(fā)車(chē)!

實(shí)例一個(gè)模擬的 Vue 應(yīng)用

首先,我們需要編寫(xiě)我們的入口文件 index.js,該文件很普通主要就是實(shí)例一個(gè)模擬的 Vue 應(yīng)用:

// index.js
// 我們?cè)?webpack.config.js 中進(jìn)行了配置,所以這里優(yōu)先在當(dāng)前目錄下尋找 vue 文件,也就是我們的 vue/index.js 文件
import Vue from "vue"; 
let vm = new Vue({
  el: "#app",
  data() {
    return {
      title: "學(xué)生列表",
      classNum: 1,
      teacher: ["張三", "李四"],
      info: {
        a: {
          b: 1
        }
      },
      students: [
        {
          id: 1,
          name: "小紅"
        },
        {
          id: 2,
          name: "小明"
        }
      ]
    };
  }
});
console.log(vm);

vue/index.js 文件主要是負(fù)責(zé)初始化內(nèi)容

// src/sindex.js
import { initState } from "./init";
function Vue(options) {
  this._init(options);
}
Vue.prototype._init = function (options) {
  // this 指向當(dāng)前實(shí)例對(duì)象
  var vm = this;
  // 我們把 new Vue() 時(shí)候傳遞的數(shù)據(jù)統(tǒng)稱為 options
  // 并且掛載到 Vue 的實(shí)例對(duì)象上
  vm.$options = options;
  // 調(diào)用 initState 初始化 data 數(shù)據(jù)
  initState(vm);
};
export default Vue;

initState方法

vue/init.js 文件暴露出一個(gè)initState方法,該方法主要是處理初始化的數(shù)據(jù):

// vue/init.js
import proxyData from "./proxy";
import observer from "./observe"
function initState(vm) {
  var options = vm.$options;
  // 如果 options 中存在 data 屬性,我們才會(huì)繼續(xù)處理
  if (options.data) {
    initData(vm);
  }
}
function initData(vm) {
  var data = vm.$options.data;
  // 把 data 數(shù)據(jù)單獨(dú)保存到 Vue 的實(shí)例化對(duì)象上,方便我們獲取
  // 如果 data 是一個(gè)函數(shù),我們需要執(zhí)行返回得到返回的對(duì)象
  data = vm._data = typeof data === "function" ? data.call(vm) : data || {};
  // 遍歷 data 對(duì)象,通過(guò) proxyData 對(duì)數(shù)據(jù)進(jìn)行攔截
  for (const key in data) {
    // 傳入的參數(shù)分別是:當(dāng)前實(shí)例、key值(也就是 vm._data)、data 中的 key 值(例如 vm._data.title)
    proxyData(vm, "_data", key);
  }
  // 調(diào)用觀察者模式
  observer(vm._data)
}
export { 
  initState
};

以上代碼,我們通過(guò)proxyData對(duì)data中的數(shù)據(jù)進(jìn)行攔截,詳情如下:

// vue/proxy.js
function proxyData(vm, target, key) {
  // 當(dāng)訪問(wèn) vm.title 的時(shí)候轉(zhuǎn)換為 vm._data.title
  //(請(qǐng)記住這句話?。。。?
  Object.defineProperty(vm, key, {
    get: function () {
      return vm[target][key];
    },
    set: function (newVal) {
      vm[target][key] = newVal;
    }
  });
}
export default proxyData;

我們還調(diào)用了observer方法進(jìn)行事件訂閱,詳細(xì)如下:

// vue/observe.js
import Observer from "./observer"
function observe(data) {
  // 判斷只處理對(duì)象,如果不是對(duì)象直接返回
  if (typeof data !== "object" || data === null) {
    return false;
  }
  // 觀察數(shù)據(jù)
  return new Observer(data)
}
export default observe;

核心文件vue/observer.js

接下來(lái)就是我們的核心文件vue/observer.js,該文件主要負(fù)責(zé)對(duì)數(shù)據(jù)類型進(jìn)行判斷,如果是數(shù)組就需要單獨(dú)處理數(shù)組,這個(gè)我們后面再說(shuō):

// vue/observer.js
import defineReactiveData from "./reactive";
import { arrMethods } from "./array";
import observeArr from "./observeArr";
// 這個(gè)方法會(huì)在多個(gè)地方調(diào)用,請(qǐng)記住這個(gè)方法以它的作用
function Observer(data) {
  // 如果 data 是一個(gè)數(shù)組,那面需要單獨(dú)處理
  if (Array.isArray(data)) {
    // 給數(shù)組新增一層原型
    data._proto__ = arrMethods;
    // 循環(huán)數(shù)組的每一項(xiàng),然后讓每一項(xiàng)都調(diào)用 Observer 方法進(jìn)行訂閱
    observeArr(data)
  } else {
    // 處理對(duì)象
    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 數(shù)據(jù)
    // 分別傳入?yún)?shù)為:vm._data、data 中的 key、data 中 key 對(duì)應(yīng)的 value
    defineReactiveData(data, key, value);
  }
};
export default Observer;

以上代碼,我們分別對(duì)數(shù)組和對(duì)象執(zhí)行不同的操作,我們先來(lái)看對(duì)象的操作:

Observer構(gòu)造函數(shù)中我們新增了一個(gè)walk方法,該方法獲取到了所有的key值,然后調(diào)用了defineReactiveData進(jìn)行處理。

// vue/reactive.js
import observe from "./observe";
function defineReactiveData(data, key, value) {
  // 例如 info.a 還是個(gè)對(duì)象,那么就遞歸觀察
  observe(value);
  // 這里的 data 是 vm._data,所以這里攔截的也是 vm._data
  Object.defineProperty(data, key, {
    get() {
      console.log(`?? 響應(yīng)式獲取:data.${key},`, value);
      return value;
    },
    set(newVal) {
      console.log(`?? 響應(yīng)式設(shè)置:data.${key},`, newVal);
      if (newVal === value) {
        return false;
      }
      // 如果新值還是對(duì)象,那么接著進(jìn)行觀察
      observe(newVal);
      value = newVal;
    }
  });
}
export default defineReactiveData;

以上代碼,我們是對(duì)vm._data進(jìn)行攔截的,這是因?yàn)槲覀兦懊嬲f(shuō)的proxyData攔截的是vm對(duì)象,當(dāng)訪問(wèn)vm.title的時(shí)候,proxyData的攔截就會(huì)生效,而proxyData內(nèi)部是通過(guò)vm._data來(lái)獲取的,這樣又會(huì)觸發(fā)defineReactiveData的攔截!

vue/observer.js文件對(duì)數(shù)組進(jìn)行處理

回到vue/observer.js文件,我們還需要對(duì)數(shù)組進(jìn)行處理:

import defineReactiveData from "./reactive";
import { arrMethods } from "./array";
import observeArr from "./observeArr";
// 這個(gè)方法會(huì)在多個(gè)地方調(diào)用,請(qǐng)記住這個(gè)方法以它的作用
function Observer(data) {
  // 如果 data 是一個(gè)數(shù)組,那面需要單獨(dú)處理
  if (Array.isArray(data)) {
    // 為數(shù)組更改原型
    data._proto__ = arrMethods;
    // 循環(huán)數(shù)組的每一項(xiàng),然后讓每一項(xiàng)都調(diào)用 Observer 方法進(jìn)行訂閱
    observeArr(data)
  } else {
   // ...
  }
}
Observer.prototype.walk = function (data) {
  // ...
};
export default Observer;

以上代碼我們對(duì)數(shù)組更改一個(gè)原型arrMethods,那看看它到底做了什么事情:

// vue/array.js
// ARR_METHODS 是一些可以更改數(shù)組本身的方法,里面包括以下內(nèi)容,我們就不展開(kāi)看了
// ["push", "pop", "shift", "unshift", "splic", "sort", "reverse"]
import { ARR_METHODS } from "./config";
import observeArr from "./observeArr";
// 把數(shù)組本身的元素進(jìn)行拷貝
var originArrayMethods = Array.prototype;
// 創(chuàng)建一個(gè)空對(duì)象,該空對(duì)象的原型就是數(shù)組的原型
var arrMethods = Object.create(originArrayMethods);
// 遍歷這些數(shù)組的方法名稱
ARR_METHODS.forEach(function (m) {
  // 在新對(duì)象上重寫(xiě)數(shù)組的方法
  arrMethods[m] = function () {
    // 把數(shù)組接到的參數(shù)轉(zhuǎn)換為一個(gè)數(shù)組
    var args = Array.prototype.slice.call(arguments);
    // 執(zhí)行數(shù)組原本的方法
    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;
    }
    // 如果有值那面就調(diào)用 observeArr 方法
    // observeArr 方法就是循環(huán)數(shù)組的每一項(xiàng),然后讓每一項(xiàng)都調(diào)用 Observer 方法進(jìn)行訂閱
    newArr && observeArr(newArr);
    return rt;
  };
});
export { arrMethods };

以上代碼我們重寫(xiě)了數(shù)組相關(guān)的方法,這是因?yàn)檫@些方法被并不能被Object.defineProperty攔截到。

詳細(xì)請(qǐng)看:v-for 列表循環(huán)

所以我們通過(guò)重寫(xiě)方法的方式,讓數(shù)組可以正常的執(zhí)行方法,同時(shí)也能被我們的observeArr方法攔截到,所以數(shù)組現(xiàn)在就是這樣多了一層我們寫(xiě)的原型,但最終它還是繼承于Array構(gòu)造函數(shù)的:

而我們的observeArr只是遍歷了數(shù)組的每一項(xiàng),讓每一項(xiàng)都進(jìn)行了攔截:

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

然后我們?nèi)?code>index.js文件獲取屬性,看看結(jié)果:

import Vue from "vue";
let vm = new Vue({
  el: "#app",
  data() {
    return {
      title: "學(xué)生列表",
      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 中的數(shù)據(jù)劫持簡(jiǎn)寫(xiě)示例的詳細(xì)內(nèi)容,更多關(guān)于Vue2 數(shù)據(jù)劫持的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 基于vue、react實(shí)現(xiàn)倒計(jì)時(shí)效果

    基于vue、react實(shí)現(xiàn)倒計(jì)時(shí)效果

    這篇文章主要為大家詳細(xì)介紹了基于vue、react實(shí)現(xiàn)倒計(jì)時(shí)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • 淺析Proxy如何實(shí)現(xiàn)Vue響應(yīng)式

    淺析Proxy如何實(shí)現(xiàn)Vue響應(yīng)式

    這篇文章主要是來(lái)和大家探討一下,Vue的響應(yīng)式系統(tǒng)僅僅是一個(gè)Proxy嗎,本文將圍繞此問(wèn)題探索一下Proxy是如何實(shí)現(xiàn)Vue響應(yīng)式的,感興趣的小伙伴可以了解一下
    2023-08-08
  • 使用vue實(shí)現(xiàn)grid-layout功能實(shí)例代碼

    使用vue實(shí)現(xiàn)grid-layout功能實(shí)例代碼

    這篇文章主要介紹了使用vue實(shí)現(xiàn)grid-layout功能的代碼講解,需要的朋友可以參考下
    2018-01-01
  • VUE 單頁(yè)面使用 echart 窗口變化時(shí)的用法

    VUE 單頁(yè)面使用 echart 窗口變化時(shí)的用法

    這篇文章主要介紹了VUE 單頁(yè)面使用 echart 窗口變化時(shí)的用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-07-07
  • this.$router.push攜帶參數(shù)跳轉(zhuǎn)頁(yè)面的實(shí)現(xiàn)代碼

    this.$router.push攜帶參數(shù)跳轉(zhuǎn)頁(yè)面的實(shí)現(xiàn)代碼

    這篇文章主要介紹了this.$router.push攜帶參數(shù)跳轉(zhuǎn)頁(yè)面,this.$router.push進(jìn)行頁(yè)面跳轉(zhuǎn)時(shí),攜帶參數(shù)有params和query兩種方式,本文結(jié)合實(shí)例代碼給大家詳細(xì)講解,需要的朋友可以參考下
    2023-04-04
  • vue實(shí)現(xiàn)價(jià)格日歷效果

    vue實(shí)現(xiàn)價(jià)格日歷效果

    這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)價(jià)格日歷效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-04-04
  • 使用vue和element-ui上傳圖片及視頻文件方式

    使用vue和element-ui上傳圖片及視頻文件方式

    這篇文章主要介紹了使用vue和element-ui上傳圖片及視頻文件方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • 淺談Vue.js 關(guān)于頁(yè)面加載完成后執(zhí)行一個(gè)方法的問(wèn)題

    淺談Vue.js 關(guān)于頁(yè)面加載完成后執(zhí)行一個(gè)方法的問(wèn)題

    這篇文章主要介紹了Vue.js 關(guān)于頁(yè)面加載完成后執(zhí)行一個(gè)方法的問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • Vue-CLI多頁(yè)分目錄打包的步驟記錄

    Vue-CLI多頁(yè)分目錄打包的步驟記錄

    這篇文章主要給大家介紹了關(guān)于Vue-CLI多頁(yè)分目錄打包的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • vue 組件 全局注冊(cè)和局部注冊(cè)的實(shí)現(xiàn)

    vue 組件 全局注冊(cè)和局部注冊(cè)的實(shí)現(xiàn)

    下面小編就為大家分享一篇vue 組件 全局注冊(cè)和局部注冊(cè)的實(shí)現(xiàn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-02-02

最新評(píng)論

菏泽市| 富裕县| 化州市| 盈江县| 昌吉市| 黄骅市| 务川| 恩平市| 百色市| 雅江县| 汕尾市| 洪江市| 乐陵市| 凤台县| 平谷区| 台湾省| 宜宾县| 嵊泗县| 文化| 富顺县| 汝阳县| 佛冈县| 诸暨市| 新河县| 湘西| 南丹县| 龙泉市| 迭部县| 连城县| 台东市| 兴业县| 客服| 深圳市| 循化| 吴堡县| 汤原县| 德阳市| 泾源县| 苏尼特右旗| 色达县| 搜索|