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

ES6使用新特性Proxy實(shí)現(xiàn)的數(shù)據(jù)綁定功能實(shí)例

 更新時(shí)間:2020年05月11日 09:13:18   作者:jrainlau  
這篇文章主要介紹了ES6使用新特性Proxy實(shí)現(xiàn)的數(shù)據(jù)綁定功能,結(jié)合具體實(shí)例形式分析了ES6使用Proxy實(shí)現(xiàn)數(shù)據(jù)綁定具體原理、操作步驟與相關(guān)注意事項(xiàng),需要的朋友可以參考下

本文實(shí)例講述了ES6使用新特性Proxy實(shí)現(xiàn)的數(shù)據(jù)綁定功能。分享給大家供大家參考,具體如下:

項(xiàng)目地址:https://github.com/jrainlau/mog
在線體驗(yàn):https://codepen.io/jrainlau/pen/YpyBBY


作為一個(gè)前端開發(fā)者,曾踩了太多的“數(shù)據(jù)綁定”的坑。在早些時(shí)候,都是通過jQuery之類的工具手動(dòng)完成這些功能,但是當(dāng)數(shù)據(jù)量非常大的時(shí)候,這些手動(dòng)的工作讓我非常痛苦。直到使用了VueJS,這些痛苦才得以終結(jié)。

VueJS的其中一個(gè)賣點(diǎn),就是“數(shù)據(jù)綁定”。使用者無需關(guān)心數(shù)據(jù)是怎么綁定到dom上面的,只需要關(guān)注數(shù)據(jù)就好,因?yàn)?code>VueJS已經(jīng)自動(dòng)幫我們完成了這些工作。

這真的非常神奇,我不可救藥地愛上了VueJS,并且把它用到我自己的項(xiàng)目當(dāng)中。隨著使用的深入,我更加想知道它深入的原理是什么。

VueJS是如何進(jìn)行數(shù)據(jù)綁定的?

通過閱讀官方文檔,我看到了下面這段話:

把一個(gè)普通 Javascript 對(duì)象傳給 Vue 實(shí)例來作為它的 data 選項(xiàng),Vue 將遍歷它的屬性,用 Object.defineProperty 將它們轉(zhuǎn)為 getter/setter。

關(guān)鍵詞是Object.definProperty,在MDN文檔里面是這么說的:

Object.defineProperty()方法直接定義一個(gè)對(duì)象的屬性,或者修改對(duì)象當(dāng)中一個(gè)已經(jīng)存在的屬性,并返回這個(gè)對(duì)象。

讓我們寫個(gè)例子來測(cè)試一下它。

首先,建立一個(gè)鋼鐵俠對(duì)象并賦予他一些屬性:

let ironman = {
 name: 'Tony Stark',
 sex: 'male',
 age: '35'
}

現(xiàn)在我們使用Object.defineProperty()方法來對(duì)他的一些屬性進(jìn)行修改,并且在控制臺(tái)把所修改的內(nèi)容輸出:

Object.defineProperty(ironman, 'age', {
 set (val) {
  console.log(`Set age to ${val}`)
  return val
 }
})

ironman.age = '48'
// --> Set age to 48

看起來挺完美的。如果把console.log('Set age to ${val}')改為element.innerHTML = val,是不是就意味著數(shù)據(jù)綁定已經(jīng)完成了呢?

讓我們?cè)傩薷囊幌落撹F俠的屬性:

let ironman = {
 name: 'Tony Stark',
 sex: 'male',
 age: '35',
 hobbies: ['girl', 'money', 'game']
}

嗯……他就是一個(gè)花花公子?,F(xiàn)在我想把一些“愛好”添加到他身上,并且在控制臺(tái)看到對(duì)應(yīng)的輸出:

Object.defineProperty(ironman.hobbies, 'push', {
 value () {
  console.log(`Push ${arguments[0]} to ${this}`)
  this[this.length] = arguments[0]
 }
})

ironman.hobbies.push('wine')
console.log(ironman.hobbies)

// --> Push wine to girl,money,game
// --> [ 'girl', 'money', 'game', 'wine' ]

在此之前,我是使用get()方法去追蹤對(duì)象的屬性變化,但是對(duì)于一個(gè)數(shù)組,我們不能使用這個(gè)方法,而是使用value()方法來代替。雖然這招也靈,但是并非最好的辦法。有沒有更好的方法可以簡(jiǎn)化這些追蹤對(duì)象或數(shù)組屬性變化的方法呢?

在ECMA2015,Proxy是一個(gè)不錯(cuò)的選擇

什么是Proxy?在MDN文檔中是這么說的(誤):

Proxy可以理解成,在目標(biāo)對(duì)象之前架設(shè)一層“攔截”,外界對(duì)該對(duì)象的訪問,都必須先通過這層攔截,因此提供了一種機(jī)制,可以對(duì)外界的訪問進(jìn)行過濾和改寫。

Proxy是ECMA2015的一個(gè)新特性,它非常強(qiáng)大,但我并不會(huì)討論太多關(guān)于它的東西,除了我們現(xiàn)在需要的一個(gè)?,F(xiàn)在讓我們一起來新建一個(gè)Proxy實(shí)例:

let ironmanProxy = new Proxy(ironman, {
 set (target, property, value) {
  target[property] = value
  console.log('change....')
  return true
 }
})

ironmanProxy.age = '48'
console.log(ironman.age)

// --> change....
// --> 48

符合預(yù)期。那么對(duì)于數(shù)組呢?

let ironmanProxy = new Proxy(ironman.hobbies, {
 set (target, property, value) {
  target[property] = value
  console.log('change....')
  return true
 }
})

ironmanProxy.push('wine')
console.log(ironman.hobbies)

// --> change...
// --> change...
// --> [ 'girl', 'money', 'game', 'wine' ]

仍然符合預(yù)期!但是為什么輸出了兩次change...呢?因?yàn)槊慨?dāng)我觸發(fā)push()方法的時(shí)候,這個(gè)數(shù)組的length屬性和body內(nèi)容都被修改了,所以會(huì)引起兩次變化。

實(shí)時(shí)數(shù)據(jù)綁定

解決了最核心的問題,可以考慮其他的問題了。

想象一下,我們有一個(gè)模板和數(shù)據(jù)對(duì)象:

<!-- html template -->
<p>Hello, my name is {{name}}, I enjoy eatting {{hobbies.food}}</p>

<!-- javascript -->
let ironman = {
 name: 'Tony Stark',
 sex: 'male',
 age: '35',
 hobbies: {
  food: 'banana',
  drink: 'wine'
 }
}

通過前面的代碼,我們知道如果想要追蹤一個(gè)對(duì)象的屬性變化,我們應(yīng)該把這個(gè)屬性作為第一個(gè)參數(shù)傳入Proxy實(shí)例。讓我們一起來創(chuàng)建一個(gè)返回新的Proxy實(shí)例的函數(shù)吧!

function $setData (dataObj, fn) {
  let self = this
  let once = false
  let $d = new Proxy(dataObj, {
   set (target, property, value) {
    if (!once) {
     target[property] = value
     once = true
     /* Do something here */
    }
    return true
   }
  })
  fn($d)
 }

它可以通過以下的方式被使用:

$setData(dataObj, ($d) => {
 /* 
  * dataObj.someProps = something
  */
})

// 或者

$setData(dataObj.arrayProps, ($d) => {
 /* 
  * dataObj.push(something)
  */
})

除此之外,我們應(yīng)該實(shí)現(xiàn)模板對(duì)數(shù)據(jù)對(duì)象的映射,這樣才能用Tony Stark來替換{{name}}

function replaceFun(str, data) {
  let self = this
  return str.replace(/{{([^{}]*)}}/g, (a, b) => {
   return data[b]
  })
 }

replaceFun('My name is {{name}}', { name: 'xxx' })
// --> My name is xxx

這個(gè)函數(shù)對(duì)于如{ name: 'xx', age: 18 }的單層屬性對(duì)象運(yùn)行良好,但是對(duì)于如{ hobbies: { food: 'apple', drink: 'milk' } }這樣的多層屬性對(duì)象卻無能為力。舉個(gè)例子,如果模板關(guān)鍵字是{{hobbies.food}},那么replaceFun()函數(shù)就應(yīng)該返回data['hobbies']['food']

為了解決這個(gè)問題,再來一個(gè)函數(shù):

function getObjProp (obj, propsName) {
  let propsArr = propsName.split('.')
  function rec(o, pName) {
   if (!o[pName] instanceof Array && o[pName] instanceof Object) {
    return rec(o[pName], propsArr.shift())
   }
   return o[pName]
  }
  return rec(obj, propsArr.shift())
 }

getObjProp({ data: { hobbies: { food: 'apple', drink: 'milk' } } }, 'hobbies.food')
// --> return { food: 'apple', drink: 'milk' }

最終的replaceFun()函數(shù)應(yīng)該是下面這樣子的:

function replaceFun(str, data) {
  let self = this
  return str.replace(/{{([^{}]*)}}/g, (a, b) => {
   let r = self._getObjProp(data, b);
   console.log(a, b, r)
   if (typeof r === 'string' || typeof r === 'number') {
    return r
   } else {
    return self._getObjProp(r, b.split('.')[1])
   }
  })
 }

一個(gè)數(shù)據(jù)綁定的實(shí)例,叫做“Mog”

不為什么,就叫做“Mog”。

class Mog {
 constructor (options) {
  this.$data = options.data
  this.$el = options.el
  this.$tpl = options.template
  this._render(this.$tpl, this.$data)
 }

 $setData (dataObj, fn) {
  let self = this
  let once = false
  let $d = new Proxy(dataObj, {
   set (target, property, value) {
    if (!once) {
     target[property] = value
     once = true
     self._render(self.$tpl, self.$data)
    }
    return true
   }
  })
  fn($d)
 }

 _render (tplString, data) {
  document.querySelector(this.$el).innerHTML = this._replaceFun(tplString, data)
 }

 _replaceFun(str, data) {
  let self = this
  return str.replace(/{{([^{}]*)}}/g, (a, b) => {
   let r = self._getObjProp(data, b);
   console.log(a, b, r)
   if (typeof r === 'string' || typeof r === 'number') {
    return r
   } else {
    return self._getObjProp(r, b.split('.')[1])
   }
  })
 }

 _getObjProp (obj, propsName) {
  let propsArr = propsName.split('.')
  function rec(o, pName) {
   if (!o[pName] instanceof Array && o[pName] instanceof Object) {
    return rec(o[pName], propsArr.shift())
   }
   return o[pName]
  }
  return rec(obj, propsArr.shift())
 }

}

使用:

<!-- html -->

  <div id="app">
   <p>
    Hello everyone, my name is <span>{{name}}</span>, I am a mini <span>{{lang}}</span> framework for just <span>{{work}}</span>. I can bind data from <span>{{supports.0}}</span>, <span>{{supports.1}}</span> and <span>{{supports.2}}</span>. What's more, I was created by <span>{{info.author}}</span>, and was written in <span>{{info.jsVersion}}</span>. My motto is "<span>{{motto}}</span>".
   </p>
  </div>
  <div id="input-wrapper">
   Motto: <input type="text" id="set-motto" autofocus>
  </div>
<!-- javascript -->

let template = document.querySelector('#app').innerHTML

let mog = new Mog({
 template: template,
 el: '#app',
 data: {
  name: 'mog',
  lang: 'javascript',
  work: 'data binding',
  supports: ['String', 'Array', 'Object'],
  info: {
   author: 'Jrain',
   jsVersion: 'Ecma2015'
  },
  motto: 'Every dog has his day'
 }
})

document.querySelector('#set-motto').oninput = (e) => {
 mog.$setData(mog.$data, ($d) => {
  $d.motto = e.target.value
 })
}

你可以在這里進(jìn)行在線體驗(yàn)。

后記

Mog僅僅是一個(gè)用于學(xué)習(xí)數(shù)據(jù)綁定的實(shí)驗(yàn)性質(zhì)的項(xiàng)目,代碼仍然不夠優(yōu)雅,功能也不夠豐富。但是這個(gè)小玩具讓我學(xué)習(xí)了很多。如果你對(duì)它有興趣,歡迎到這里把項(xiàng)目fork走,并且加入一些你的想法。

感謝閱讀!

感興趣的朋友可以使用在線HTML/CSS/JavaScript代碼運(yùn)行工具http://tools.jb51.net/code/HtmlJsRun測(cè)試上述代碼運(yùn)行效果。

更多關(guān)于JavaScript相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《javascript面向?qū)ο笕腴T教程》、《JavaScript錯(cuò)誤與調(diào)試技巧總結(jié)》、《JavaScript數(shù)據(jù)結(jié)構(gòu)與算法技巧總結(jié)》、《JavaScript遍歷算法與技巧總結(jié)》及《JavaScript數(shù)學(xué)運(yùn)算用法總結(jié)

希望本文所述對(duì)大家JavaScript程序設(shè)計(jì)有所幫助。

相關(guān)文章

  • UNiapp 微信小程序漸變不生效的解決方案

    UNiapp 微信小程序漸變不生效的解決方案

    這篇文章主要介紹了UNiapp 微信小程序漸變不生效的解決方案,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-07-07
  • JS動(dòng)畫實(shí)現(xiàn)回調(diào)地獄promise的實(shí)例代碼詳解

    JS動(dòng)畫實(shí)現(xiàn)回調(diào)地獄promise的實(shí)例代碼詳解

    這篇文章主要介紹了JS動(dòng)畫實(shí)現(xiàn)回調(diào)地獄promise的實(shí)例代碼詳解,需要的朋友可以參考下
    2018-11-11
  • Cropper.js入門之在HTML中實(shí)現(xiàn)交互式圖像裁剪

    Cropper.js入門之在HTML中實(shí)現(xiàn)交互式圖像裁剪

    這篇文章主要為大家介紹了Cropper.js入門之在HTML中實(shí)現(xiàn)交互式圖像裁剪示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • 微信小程序?qū)崿F(xiàn)登陸注冊(cè)滑塊驗(yàn)證

    微信小程序?qū)崿F(xiàn)登陸注冊(cè)滑塊驗(yàn)證

    這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)登陸注冊(cè)滑塊驗(yàn)證,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • js獲取騰訊視頻ID的方法

    js獲取騰訊視頻ID的方法

    這篇文章主要介紹了js獲取騰訊視頻ID的方法,涉及JavaScript針對(duì)URL地址規(guī)則的分析與字符串的截取操作相關(guān)操作技巧,需要的朋友可以參考下
    2016-10-10
  • JS基于開關(guān)思想實(shí)現(xiàn)的數(shù)組去重功能【案例】

    JS基于開關(guān)思想實(shí)現(xiàn)的數(shù)組去重功能【案例】

    這篇文章主要介紹了JS基于開關(guān)思想實(shí)現(xiàn)的數(shù)組去重功能,簡(jiǎn)單分析了開關(guān)思想的原理,并結(jié)合具體實(shí)例形式分析了javascript基于開關(guān)思想實(shí)現(xiàn)數(shù)組去重相關(guān)操作技巧,需要的朋友可以參考下
    2019-02-02
  • 原生Js實(shí)現(xiàn)的畫廊功能

    原生Js實(shí)現(xiàn)的畫廊功能

    這篇文章主要介紹了原生Js實(shí)現(xiàn)的畫廊功能,幫助大家更好的理解和學(xué)習(xí)使用JavaScript,感興趣的朋友可以了解下
    2021-05-05
  • jstree的簡(jiǎn)單實(shí)例

    jstree的簡(jiǎn)單實(shí)例

    最近使用到了jstree,感覺是一款靈活的、可多項(xiàng)定制的tree插件。下面通過本文給大家詳細(xì)介紹下jstree的簡(jiǎn)單實(shí)例,需要的朋友可以參考下
    2016-12-12
  • 探索JavaScript函數(shù)的無限可能(函數(shù)基本概念)

    探索JavaScript函數(shù)的無限可能(函數(shù)基本概念)

    JavaScript中的函數(shù)是一種重要的編程概念,它允許我們封裝可重用的代碼塊,并在需要時(shí)進(jìn)行調(diào)用,本文將深入介紹JavaScript函數(shù)的各個(gè)方面,包括函數(shù)定義和調(diào)用、參數(shù)和返回值、作用域和閉包、高階函數(shù)以及常見的函數(shù)應(yīng)用場(chǎng)景,感興趣的朋友一起看看吧
    2023-08-08
  • Javascript獲取background屬性中url的值

    Javascript獲取background屬性中url的值

    Javascript獲取CSS中屬性值方法有很多,今天工作的時(shí)候遇到了一個(gè)問題是需要利用Javascript獲取css中background-img屬性u(píng)rl的值,通過查閱網(wǎng)站的資料找到了解決方法,現(xiàn)在將方法分享給大家,有需要的朋友們們可以參考借鑒,下面來一起看看吧。
    2016-10-10

最新評(píng)論

苍溪县| 贵德县| 巍山| 武鸣县| 峨边| 房产| 阿鲁科尔沁旗| 鄱阳县| 南川市| 松滋市| 耒阳市| 崇义县| 桦甸市| 包头市| 乌兰察布市| 琼海市| 武平县| 河东区| 天全县| 进贤县| 大港区| 祁东县| 射阳县| 洛扎县| 三台县| 孙吴县| 稻城县| 济源市| 化隆| 淄博市| 台北市| 揭阳市| 洮南市| 增城市| 兰坪| 新建县| 涪陵区| 清河县| 商水县| 雅江县| 湘西|