【Vue】原始碼分析--雙向資料繫結的實現
總結
Vue的雙向資料繫結主要通過Object.defineProperty來實現,先為所有的屬性加上get/set的監控,這樣當屬性值改變時就會觸發對應的set方法,然後再在set方法中通過觀察者來更新檢視,同時在get方法中進行依賴收集。
極簡版的實現
- index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" >
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>極簡雙向資料繫結</title>
</head>
<body>
<input type="text" id="message" />
<div id="msg"></div>
<script src="app.js"></script>
</body>
</html>
- app.js
var obj = {}
Object.defineProperty(obj, "data", {
get: function () {
console.log("get")
},
set: function (newValue) {
document.getElementById("message").value = newValue
document.getElementById("msg").innerText = newValue
}
})
document.getElementById("message").addEventListener('keyup' , function () {
obj.data = event.target.value
})
- 分析
(1)通過Object.defineProperty的方法為屬性加上get/set的監控
(2)通過EventListener監聽屬性的改變,不斷觸發屬性的set方法,從而實現資料的雙向繫結
稍微複雜版的實現
- index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>雙向資料繫結</title>
</head>
<body>
<div id="app">
<input type="text" v-model="message">
{{ message }}
</div>
<script src="dist/bundle.js"></script>
</body>
</html>
- main.js
import myVue from './myVue'
new myVue({
el: '#app',
data: {
message: "hello myVue"
}
})
- myVue.js
import Observer from './Observer'
import Compiler from './Compiler'
class myVue {
constructor(options) {
// 獲取物件傳入的資料
this.$options = options
this.$el = this.$options.el
this._data = this.$options.data
// 將傳入的所有屬性新增get/set的屬性監聽
// 屬性值發生改變會觸發set方法
Object.keys(this._data).forEach(key=>{
this.add_watch(key)
})
// 將所有屬性加入訂閱釋出者模式的管理中
new Observer(this._data)
// 編譯渲染頁面
new Compiler(this.$el, this)
}
add_watch(key) {
var self = this
Object.defineProperty(this, key, {
get() {
return self._data[key]
},
set(value) {
self._data[key] = value
}
})
}
}
export default myVue
- Observer.js
import Dep from './Dep'
class Observer {
constructor(data) {
// 獲取所有屬性資料
this.data = data
// 為所有屬性資料新增get/sete的屬性監聽
Object.keys(this.data).forEach(key=>{
this._bind(data, key, data[key])
})
}
_bind(data, key, val) {
var myDep = new Dep()
Object.defineProperty(data, key, {
get() {
// 如果是為訂閱的物件,則添訂閱
if(Dep.target) myDep.listen(Dep.target)
return val
},
set(newValue) {
if (newValue === val) return
val = newValue
// 如果數值改變,則釋出更新
myDep.notify()
}
})
}
}
export default Observer
- Watcher.js
import Dep from './Dep'
class Watcher {
constructor(node, name, vm) {
this.node = node
this.name = name
this.vm = vm
Dep.target = this
this.update()
Dep.target = null
}
update() {
this.node.nodeValue = this.vm[this.name]
}
}
export default Watcher
- Dep.js
class Dep {
constructor() {
this.list = []
}
listen(subs) {
this.list.push(subs)
}
notify() {
for(var i=0; i<this.list.length; i++){
this.list[i].update()
}
}
}
Dep.prototype.target = null
export default Dep
- Compiler.js
import Watcher from './Watcher'
const REG = /\{\{(.*)\}\}/
class Compiler {
constructor(el, vm) {
this.el = document.querySelector(el)
this.vm = vm
// 建立文件片段,編譯完成後,掛載到el元素上
this.frag = this._createFragment()
this.el.appendChild(this.frag)
}
_createFragment() {
var frag = document.createDocumentFragment()
var child
while (child = this.el.firstChild) {
this._compile(child)
frag.appendChild(child)
}
return frag
}
_compile(node) {
// 如果傳入的是節點node
if(node.nodeType === 1) {
var attr = node.attributes
var self = this
if(attr.hasOwnProperty('v-model')){
var name = attr['v-model'].nodeValue
node.addEventListener('input', function(e) {
self.vm[name] = e.target.value
})
node.value = this.vm[name]
}
}
// 如果傳入的是元素elemet
if (node.nodeType === 3) {
if(REG.test(node.nodeValue)) {
var name = RegExp.$1
name = name.trim()
new Watcher(node, name, this.vm)
}
}
}
}
export default Compiler
相關推薦
【Vue】原始碼分析--雙向資料繫結的實現
總結 Vue的雙向資料繫結主要通過Object.defineProperty來實現,先為所有的屬性加上get/set的監控,這樣當屬性值改變時就會觸發對應的set方法,然後再在set方法中通過觀
【Vue.js學習筆記】5:雙向資料繫結,計算屬性
雙向資料繫結 雙向資料繫結往往會用到input、select、textarea等表單標籤上,因為總是涉及一個數據資料的地方和輸出資料的地方。 當資料發生變化的時候,檢視也就發生變化,當檢視發生變化的時候,資料也會跟著同步變化。 資料雙向繫結,一定是對於UI控制元件來說的,
【Vue】原始碼分析--vdom與html的相互轉換
簡析 vdom是由js物件節點組成的一個樹狀結構,通過diff演算法對比js物件節點來更新,最後對映到原生的dom中 一個簡單的dom結構 <div id="container">
vue.js v-model雙向資料繫結, vue.js form表單資料繫結
vue.js v-model雙向資料繫結, vue.js form表單資料繫結 ================================ ©Copyright 蕃薯耀 2018年11月29日 http://fanshuyao.iteye.com/ &l
vue指令v-model(雙向資料繫結)自動收集資料
前言:表單提交資料在網站頁面中是十分常見的,而這個表單資料的獲取在原生寫法甚至於JQ都是比較麻煩的(首先需要獲取DOM,然後獲取值)。 但是,在vue的專案環境下,表單資料的收集又該怎麼辦呢?(這種自己寫input元素的方法在實際專案中是不常用的哈,因為一般我們都會用一個UI庫,方便而快捷!
vue.js和angular雙向資料繫結的實現原理
一、vue雙向資料繫結 1、原理 資料劫持: vue.js 是採用資料劫持結合釋出者-訂閱者模式的方式,通過Object.defineProperty()來劫持各個屬性的setter,getter,在資料變動時釋出訊息給訂閱者,觸發相應的監聽回撥。 2、實現步驟 要實現mv
Vue 雙向資料繫結實現
<!DOCTYPE html> <html> <head> <title>myVue</title> <style> #app{ text-align: center;
Vue渲染原理及其雙向資料繫結詳解
雙向資料繫結原理 1. 新建vue例項 var data = { text:'hello world!' }; var vm = new Vue({
Vue.js雙向資料繫結實現
js中物件屬性型別有資料屬性和訪問器屬性,這裡實現簡單的雙向資料繫結是利用了物件的訪問器屬性中包含的get和set 修改屬性的預設特性使用Object.defineProperty()方法 addEventListener(event,function,useCapture
vue的思中雙向資料繫結的原理
我們在面試中經常會被問道什麼是mvc 什麼是 mvvm 還有雙向資料繫結的原理:MVC:對專案的整體把控,M代表的是資料庫中的資料,V代表的是前端的檢視層,C用於處理M和V之間進行互動的業務邏輯(業務
雙向資料繫結實現之Object.defineProperty
vue.js利用的是es5的 defineproperty 特性實現的雙向資料繫結,瞭解一下基本原理。 舉例 var person= {}; Object.defineProperty(person, "name", { v
【react】react實現類似vue的雙向資料繫結
import React from 'react' import ReactDOM from 'react-dom' class Comment extends React.Component { constructor() { sup
深入vue原始碼,瞭解vue的雙向資料繫結原理
大家都知道vue是一種MVVM開發模式,資料驅動檢視的前端框架,並且內部已經實現了雙向資料繫結,那麼雙向資料繫結是怎麼實現的呢? 先手動擼一個最最最簡單的雙向資料繫結 1 <div> 2 <input type="text" name="" id="te
【Android】原始碼分析 - LRUCache快取實現原理
一、Android中的快取策略 一般來說,快取策略主要包含快取的新增、獲取和刪除這三類操作。如何新增和獲取快取這個比較好理解,那麼為什麼還要刪除快取呢?這是因為不管是記憶體快取還是硬碟快取,它們的快取大小都是有限的。當快取滿了之後,再想其新增快取,這個時候就需要刪除一些舊的快取
【Android】原始碼分析 - View事件分發機制
事件分發物件 (1)所有 Touch 事件都被封裝成了 MotionEvent 物件,包括 Touch 的位置、時間、歷史記錄以及第幾個手指(多指觸控)等。 (2)事件型別分為 ACTION_DOWN, ACTION_UP,ACTION_MOVE,ACTION_POINTER_D
【Android】原始碼分析 - Activity啟動流程
啟動Activity的方式 Activity有2種啟動的方式,一種是在Launcher介面點選應用的圖示、另一種是在應用中通過Intent進行跳轉。我們主要介紹與後者相關的啟動流程。 Intent intent = new Intent(this, TestActivity
面試題:你能寫一個Vue的雙向資料繫結嗎?
在目前的前端面試中,vue的雙向資料繫結已經成為了一個非常容易考到的點,即使不能當場寫出來,至少也要能說出原理。本篇文章中我將會仿照vue寫一個雙向資料繫結的例項,名字就叫myVue吧。結合註釋,希望能讓大家有所收穫。 1、原理 Vue的雙向資料繫結的原理相信大家也都十分了解了,主要是通過 Obje
轉 vue實現雙向資料繫結之原理及實現篇 vue的雙向繫結原理及實現
轉自:canfoo#! vue的雙向繫結原理及實現 前言 先上個成果圖來吸引各位: 程式碼: &nb
Vue 框架-03-鍵盤事件、健值修飾符、雙向資料繫結
Vue 框架-03-鍵盤時間及健值修飾符 一、鍵盤事件,當按鍵盤時,在控制檯輸出提示 html 原始碼: <!DOCTYPE html> <html> <head> <meta charset="utf-8" />
Vue學習(3)————————繫結Class繫結Style,雙向資料繫結,dom節點
標籤內繫結屬性(此功能看來可以動態繫結標籤屬性) <template> <div id="app"> <div v-bind:title="title"> 滑鼠走一走 </div> </div> </temp