国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

vue2雙向數(shù)據(jù)綁定基本原理

這篇具有很好參考價(jià)值的文章主要介紹了vue2雙向數(shù)據(jù)綁定基本原理。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

vue2的雙向數(shù)據(jù)綁定(又稱響應(yīng)式)原理,是通過數(shù)據(jù)劫持結(jié)合發(fā)布訂閱模式的方式來實(shí)現(xiàn)的,通過Object.defineProperty()來劫持各個(gè)屬性的setter,getter,在數(shù)據(jù)變動(dòng)時(shí)發(fā)布消息給訂閱者,觸發(fā)相應(yīng)的監(jiān)聽回調(diào)來渲染視圖。也就是說數(shù)據(jù)和視圖同步,數(shù)據(jù)發(fā)生變化,視圖跟著變化,視圖變化,數(shù)據(jù)也隨之發(fā)生改變。

Object.defineProperty

  • 第一個(gè)參數(shù) object對(duì)象
  • 第二個(gè)參數(shù) 屬性名
  • 第三個(gè)參數(shù) 屬性描述符 這里只介紹getset
function defineReactive(data, key, value) {
    Object.defineProperty(data, key, {
        get() {
            console.log('此處進(jìn)行依賴的收集')
            return value
        },
        set(newValue) {
            if(newValue === value) return;
            console.log('此處通知變化,執(zhí)行更新操作')
            value = newValue;
        }
    })
}

const data = {
    message: '1',
    msg:'2'
}

let keys = Object.keys(data);

for(let i = 0; i< keys.length; i++) {
    let key = keys[i];
    let value = data[key];
    // 把data中的每一項(xiàng)變成響應(yīng)式數(shù)據(jù)
    defineReactive(data,key, value)
}

console.log(data.msg);
data.message = 'nihao'

vue2雙向數(shù)據(jù)綁定基本原理

從這個(gè)例子我們可以簡單理解一下數(shù)據(jù)劫持,當(dāng)我們用到了某個(gè)數(shù)據(jù)(比如在頁面上、在計(jì)算屬性中、在watch中),那么肯定會(huì)對(duì)這個(gè)數(shù)據(jù)進(jìn)行訪問,所以只要在getter中對(duì)數(shù)據(jù)的使用進(jìn)行攔截,對(duì)這個(gè)數(shù)據(jù)的使用(也就是此數(shù)據(jù)的依賴)進(jìn)行收集,收集好之后方便我們進(jìn)行后續(xù)的處理。當(dāng)我們改變某個(gè)數(shù)據(jù)的時(shí)候,需要用setter進(jìn)行攔截,對(duì)我們?cè)趃etter里面收集到的依賴進(jìn)行響處理,來改變視圖。

雙向數(shù)據(jù)綁定及模版編譯

vue初始化

  • 初始化數(shù)據(jù)
    • 初始化data
    • 初始化watch
    • 初始化computed
  • 掛載
let vm = new Vue({
  el: '#app',
  data() {
    return {
      msg:'1',
      message: 'hello',
      obj: {
        a:1,
        b:2
      }
    }
  },
  watch: {
    message: function (newValue, oldValue) {
      console.log(newValue, oldValue)
    }
  },
  computed: {
    mm: function () {
      return this.message + this.msg;
    }
  },
})
Vue.prototype._init = function(options) {
  // 保存實(shí)例
  let vm = this;
  vm.$options = options;

  initState(vm);

  if(vm.$options.el) {
    vm.$mount();
  }
}

渲染W(wǎng)atcher(RenderWatcher)依賴的收集

初始化data

  • 觀察數(shù)據(jù),把data下對(duì)象都變成響應(yīng)式數(shù)據(jù)
  • 每一個(gè)響應(yīng)式數(shù)據(jù),都有一個(gè)對(duì)應(yīng)的實(shí)例化dep,作用是對(duì)依賴進(jìn)行收集以及數(shù)據(jù)改變更新視圖

Observer

export function defineReactive(data, key, value) {
  let childOb =  observe(value) // 遞歸把對(duì)象變成響應(yīng)式

  let dep = new Dep(key);
  // 不兼容IE8及以下
  Object.defineProperty(data, key, {
    get() {
      if(Dep.target) {
        dep.depend();
        if(childOb) {
          childOb.dep.depend(); // 數(shù)組的依賴收集
          dependArray(value)
        }
      }
      return value;
    },
    set(newValue) {
      if(newValue === value) return
      observe(newValue)
      value = newValue
      dep.notify()
    }
  });
}

class Observer {
  constructor(data) {
    this.dep = new Dep();
    
    // 為了讓數(shù)組上有dep
    Object.defineProperty(data, '__ob__', {
      get: () => this
    })

    if(Array.isArray(data)) {
      // 數(shù)組單獨(dú)處理
      data.__proto__ = newArrayProtoMethods;
      observeArray(data); // 對(duì)數(shù)組本身存在的對(duì)象進(jìn)行觀察
    } else {
      this.walk(data)
    }
    
  }
  
  walk(data) {
    // 拿到key值
    let keys = Object.keys(data)
    
    for(let i = 0; i< keys.length; i++) {
      let key = keys[i]
      let value = data[key]
      // 變成響應(yīng)式數(shù)據(jù)
      defineReactive(data, key, value)
    }
  }
}

Dep

  • 對(duì)響應(yīng)數(shù)據(jù)的依賴進(jìn)行收集
  • 數(shù)據(jù)改變時(shí),對(duì)依賴進(jìn)行update處理
  • depend函數(shù)使depwatcher相互依賴
    vue2雙向數(shù)據(jù)綁定基本原理
let id = 0;

class Dep {
  constructor() {
    this.id = id++;
    this.subs = [];
  }

  // 發(fā)布訂閱模式

  // 訂閱
  addSub(watcher) {
    this.subs.push(watcher)
  }

  // 發(fā)布
  notify() {
    this.subs.forEach(watcher => watcher.update());
  }


  // 會(huì)把watcher存到dep當(dāng)中,還會(huì)把dep存到
  depend() {
    if(Dep.target) {
      Dep.target.addDep(this);
    }
  }
}



let stack = [];

// watcher進(jìn)棧
export function pushTarget(watcher) {
  Dep.target = watcher;
  stack.push(watcher)
}

// watcher出棧
export function popTarget() {
  stack.pop()
  Dep.target = stack[stack.length - 1];
}

以在頁面上渲染message為例

import Vue from 'vue';

let vm = new Vue({
  el: '#app',
  data() {
    return {
      message: 'hello',
    }
  },
})
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="app">
    {{ message }}
  </div>
</body>
</html>

$mount

  • 實(shí)例化一個(gè)RenderWatcher,傳入當(dāng)前的實(shí)例和頁面渲染函數(shù)
  • _update里面涉及到模版編譯,我們可以先忽略模版編譯的內(nèi)容,只需要知道模版編譯的時(shí)候要取實(shí)例上的對(duì)象比如vm.message
Vue.prototype.$mount = function() {
  let vm = this;
  let el = vm.$options.el;
  el = vm.$el = query(el);
  // 首次渲染組件或者因?yàn)閿?shù)據(jù)變化重新渲染組件
  let updateComponent = () => {
    vm._update();
  }
  // 渲染watcher
  new Watcher(vm, updateComponent);
}


Vue.prototype._update = function() {
  let vm = this;
  let el = vm.$el;

  // 不直接操作dom,把dom先保存到文件碎片里面,文件碎片是保存在內(nèi)存中的,把操作結(jié)果一次塞到dom中去
  let node = document.createDocumentFragment();
  let firstChild;

  while(firstChild = el.firstChild) {
    node.appendChild(firstChild);
  }

  // 編譯 處理{{ message }} -> vm.message -> 觸發(fā)message的getter -> 進(jìn)行依賴的收集
  compiler(node, vm);

  el.appendChild(node)
}

Watcher

class Watcher {
  constructor(vm , exprOrFn, cb = () => {}, opts = {}) {
    this.vm = vm;
    this.exprOrFn = exprOrFn;
    this.getter = exprOrFn;
    this.depsId = new Set()
    this.deps = []
    this.id = id++; // 每次實(shí)例化watcher的時(shí)候id++,可以通過不同的id區(qū)分不同的watcher
    this.get(); 
  }
  get() {
    pushTarget(this); // Dep.target = 當(dāng)前的watcher
    this.getter();
    popTarget();
    return value;
  }

  
  update() {
     this.get();
  }

  depend() {
    // 作用把watcher里面的addDep執(zhí)行
    let i = this.deps.length;
    while(i--) {
      this.deps[i].depend();
    }
  }

  // watcher和dep互相依賴
  addDep(dep) {
    let id = dep.id;
    if(!this.depsId.has(id)) {
      this.depsId.add(id);
      this.deps.push(dep); // 把dep存在了watcher中
      dep.addSub(this) // 把watcher存在dep中
    }
  }
}

執(zhí)行g(shù)etter的時(shí)候,先把當(dāng)前的RenderWatcherpush到stack中,并且把Dep.target設(shè)置為當(dāng)前的renderWatcher。其次時(shí)執(zhí)行渲染函數(shù),取實(shí)例上的值vm.message,這時(shí)候會(huì)走到messagesetter,執(zhí)行dep.depend()操作,depend會(huì)把當(dāng)前的dep存在RenderWatcher中,也會(huì)把當(dāng)前的renderWatcher存在dep中。執(zhí)行完后把RenderWatcherpop掉,并且把Dep.target指向前一個(gè)依賴。

vue2雙向數(shù)據(jù)綁定基本原理

改變數(shù)據(jù)

let vm = new Vue({
  el: '#app',
  data() {
    return {
      message: 'hello',
    }
  },
})

setTimeout(() =>{
  vm.message = 'hi'
}, 3000);
set(newValue) {
  if(newValue === value) return
  observe(newValue)
  value = newValue
  dep.notify()
}
notify() {
    this.subs.forEach(watcher => watcher.update());
}

改變響應(yīng)式數(shù)據(jù)的時(shí)候,會(huì)在setter里面進(jìn)行攔截,執(zhí)行dep.notify,他會(huì)循環(huán)執(zhí)行dep.subs里面保存watcher(即依賴)的update函數(shù),這里等同于get函數(shù),又會(huì)執(zhí)行同上的操作,數(shù)據(jù)的改變會(huì)導(dǎo)致視圖的變化。

用戶Watcher(UserWatcher)依賴的收集

初始化watch

let vm = new Vue({
  el: '#app',
  data() {
    return {
      message: 'hello',
    }
  },
  watch: {
    message: function (newValue, oldValue) {
      console.log(newValue, oldValue)
    }
  },
})

setTimeout(() =>{
  vm.message = 'hi'
}, 3000);
function createWatcher(vm, key, handler) {
  return vm.$watch(key, handler)
}

function initWatch(vm) {
  let watch = vm.$options.watch; // 拿到實(shí)例上的watcher
  for(let key in watch) {
    let handler = watch[key]
    createWatcher(vm, key, handler)
  }
}

Vue.prototype.$watch = function (expr, handler) {
  let vm = this;
  new Watcher(vm, expr, handler, {user: true}); // user: true  區(qū)分于渲染watcher
}

初始化watch的時(shí)候,會(huì)遍歷每一個(gè)屬性,每一個(gè)屬性都有一個(gè)實(shí)例化的watcher,這種watcher叫做UserWatcher。

class Watcher {
  constructor(vm , exprOrFn, cb = () => {}, opts = {}) {
    this.vm = vm;
    this.exprOrFn = exprOrFn;
    this.getter = function () {  
      return getValue(exprOrFn, vm)  // vm.message
    }

    if(opts.user) {
      this.user = true;
    }

    this.cb = cb;
    this.opts = opts;
    this.depsId = new Set()
    this.deps = []
    this.id = id++; // 每次實(shí)例化watcher的時(shí)候id++,可以通過不同的id區(qū)分不同的watcher

    this.value = this.get(); // 老的oldValue
  }
  get() {
    pushTarget(this); // Dep.target = 當(dāng)前的watcher
    let value = this.getter.call(this.vm);
    if(this.value !== value) {
      this.cb(value, this.value)
    }
    popTarget();
    return value;
  }

  update() {
    this.get(); 
  }
    

  run() {
    let value = this.get(); // 新的newValue
    if(this.value !== value) {
      this.cb(value, this.value)
    }
  }

  depend() {
    // 作用把watcher里面的addDep執(zhí)行
    let i = this.deps.length;
    while(i--) {
      this.deps[i].depend();
    }
  }

  // watcher和dep互相依賴
  addDep(dep) {
    let id = dep.id;

    if(!this.depsId.has(id)) {
      this.depsId.add(id);
      this.deps.push(dep); // 把dep存在了watcher中
      dep.addSub(this) // 把watcher存在dep中
    }
  }
}

實(shí)例化UserWatcher的時(shí)候,執(zhí)行get,此時(shí)Dep.target指向UserWatcher,并且stack中push這個(gè)UserWatcher,getValue的時(shí)候會(huì)取值vm.message,所以會(huì)執(zhí)行dep.depend進(jìn)行依賴的收集,此時(shí)message的dep中就存在這個(gè)userWatcher了。之后把UserWatcherstack中pop掉。

vue2雙向數(shù)據(jù)綁定基本原理

當(dāng)3s鐘后數(shù)據(jù)改變的時(shí)候,setter攔截,dep.notify(),將messge的dep中subs遍歷執(zhí)行依賴的update,又要執(zhí)行pushTarget、getter、popTareget等操作
vue2雙向數(shù)據(jù)綁定基本原理

計(jì)算屬性Watcher(ComputedWatcher)依賴的收集

初始化computed

let vm = new Vue({
  el: '#app',
  data() {
    return {
      msg:'1',
      message: 'hello',
    }
  },
  computed: {
    mm: function () {
      return this.message + this.msg;
    }
  },
})

setTimeout(() =>{
  vm.message = 'hi'
}, 3000);
function createComputedGetter(vm, key) {
  let watcher = vm._watchersComputed[key]; // 當(dāng)前的計(jì)算屬性watcher

  return function () {
    if(watcher) {
      if(watcher.dirty) {
        watcher.evaluate()
      }

      if(Dep.target) {
        watcher.depend();
      }

      return watcher.value;
    }
  }
}

function initComputed(vm, computed) {
  let watchers =  vm._watchersComputed =  Object.create(null); // 創(chuàng)建空對(duì)象,為了在實(shí)例里面更加方便的訪問到計(jì)算屬性的watcher
  for (let key in computed) {
    let userDef = computed[key];
    watchers[key] = new Watcher(vm, userDef, () => {}, {lazy: true}); // lazy: true 表明計(jì)算屬性的watcher

    Object.defineProperty(vm, key, {
      get: createComputedGetter(vm, key)
    })
  }
}
let id = 0;

class Watcher {
  constructor(vm , exprOrFn, cb = () => {}, opts = {}) {
    this.vm = vm;
    this.exprOrFn = exprOrFn;
    if(typeof exprOrFn === 'function') { // 渲染watcher的時(shí)候執(zhí)行vm._update()渲染頁面
      this.getter = exprOrFn;
    } else {
      this.getter = function () {  // 用戶watcher的時(shí)候?yàn)榱双@取到oldValue和newValue
        return getValue(exprOrFn, vm)
      }
    }

    if(opts.user) {
      this.user = true;
    }

    this.lazy = opts.lazy;
    this.dirty = opts.lazy; //  和計(jì)算屬性的緩存相關(guān),判斷需不需要重新計(jì)算, 默認(rèn)為true是需要重新計(jì)算
    this.cb = cb;
    this.opts = opts;
    this.depsId = new Set()
    this.deps = []
    this.id = id++; // 每次實(shí)例化watcher的時(shí)候id++,可以通過不同的id區(qū)分不同的watcher

    // 計(jì)算屬性一開始不去獲取值
    this.value = this.lazy ? undefined :this.get(); // 老的oldValue
  }
  get() {
    pushTarget(this); // Dep.target = 當(dāng)前的watcher
    let value = this.getter.call(this.vm);
    popTarget();
    return value;
  }

  evaluate() {
    this.value = this.get();
    this.dirty = false;
  }

  update() {
    if(this.lazy) {  // lazy判斷計(jì)算屬性的watcher
      this.dirty = true;  // dirty判斷是否重新取值
    } else { 
      // 批量更新
      queueWatcher(this); // 防止數(shù)據(jù)批量改變的時(shí)候執(zhí)行多次
      // this.get(); // 直接更新,當(dāng)數(shù)據(jù)批量改變的時(shí)候會(huì)執(zhí)行多次
    }
  }
    

  run() {
    let value = this.get(); // 新的newValue
    if(this.value !== value) {
      this.cb(value, this.value)
    }
  }

  depend() {
    // 作用把watcher里面的addDep執(zhí)行
    let i = this.deps.length;
    while(i--) {
      this.deps[i].depend();
    }
  }

  // watcher和dep互相依賴
  addDep(dep) {
    let id = dep.id;

    if(!this.depsId.has(id)) {
      this.depsId.add(id);
      this.deps.push(dep); // 把dep存在了watcher中
      dep.addSub(this) // 把watcher存在dep中
    }
  }
}

計(jì)算屬性初始化的時(shí)候,需要遍歷每一個(gè)值,每一個(gè)計(jì)算屬性都有一個(gè)對(duì)應(yīng)的實(shí)例化wathcer,這個(gè)watcher是ComputedWatcher。計(jì)算屬性和data,watch不同的是,他不能通過vm.的方式取到值,所以也要進(jìn)行攔截。當(dāng)執(zhí)行$mount的時(shí)候,先實(shí)例化一個(gè)RenderWatcher,執(zhí)行pushTarget,此時(shí)的Dep.target指向的是當(dāng)前的RenderWatcher,在執(zhí)行g(shù)etter的時(shí)候取vm.mm的值,因?yàn)檫M(jìn)行了getter攔截處理,所以會(huì)執(zhí)行watcher.evaluate,此時(shí)的Dep.target指向的是當(dāng)前的ComputedWatcher

vue2雙向數(shù)據(jù)綁定基本原理

然后執(zhí)行popTarget操作,此Dep.target指向了RenderWatcher,這時(shí)候存在一個(gè)問題,此時(shí)的依賴中update函數(shù)是不能渲染頁面的,所以要辦法在dep中存入RenderWatcher,辦法就是執(zhí)行ComputedWatcherdepend函數(shù),經(jīng)過這個(gè)操作之后messagemsg,都分別保存了兩個(gè)依賴,數(shù)據(jù)改變的時(shí)候,視圖也會(huì)改變

vue2雙向數(shù)據(jù)綁定基本原理

小結(jié)

Observer

  • 使用Object.defineProperty把data數(shù)據(jù)變成響應(yīng)式對(duì)象,使每一個(gè)對(duì)象都對(duì)應(yīng)的實(shí)例化dep
  • 在getter中進(jìn)行依賴的收集,即dep.depend()
  • 在setter中進(jìn)行派發(fā)更新,即dep.notify()

Dep

  • Watcher實(shí)例的管理器
  • Dep.target指向的是當(dāng)前的Watcher實(shí)例
  • depend()方法會(huì)將當(dāng)前的dep實(shí)例保存到watcher中,也會(huì)保存當(dāng)前的watcher

Watcher

  • 它是一個(gè)觀察者,數(shù)據(jù)改變的時(shí)候執(zhí)行更新操作
  • 有三種RenderWatcher、UserWatcher、ComputedWatcher
  • 數(shù)據(jù)變 -> 使用數(shù)據(jù)的視圖變 -> RenderWatcher
  • 數(shù)據(jù)變 -> 使用數(shù)據(jù)的計(jì)算屬性變 -> 使用計(jì)算屬性的視圖變 -> ComputedWatcher
  • 數(shù)據(jù)變 -> 開發(fā)者主動(dòng)注冊(cè)的回調(diào)函數(shù)執(zhí)行 -> UserWatcher

模版編譯及v-model的簡單實(shí)現(xiàn)

這里不涉及虛擬DOM等復(fù)雜邏輯,只是簡單替換

Vue.prototype._update = function() {
  let vm = this;
  let el = vm.$el;

  // 不直接操作dom,把dom先保存到文件碎片里面,文件碎片是保存在內(nèi)存中的,把操作結(jié)果一次塞到dom中去
  let node = document.createDocumentFragment();
  let firstChild;

  while(firstChild = el.firstChild) {
    node.appendChild(firstChild);
  }

  // 編譯 處理{{ message }} -> vm.message
  compiler(node, vm);

  el.appendChild(node)
}

el下的節(jié)點(diǎn)都保存到文件碎片中,經(jīng)過編譯之后差值表達(dá)式里面的內(nèi)容會(huì)被替換成真正的數(shù)據(jù),在把結(jié)果添加到dom上

const reg = /\{\{((?:.|\r?\n)+?)\}\}/g; // 任意字符或者換行 ?: 表是不捕獲分組

export function compiler (node, vm) {
  let childNodes = node.childNodes;
  // 把類數(shù)組轉(zhuǎn)換成數(shù)組
  let childNodesArray = [...childNodes];
  
  childNodesArray.forEach(child => {
    if(child.nodeType === 1) {
      if(child.hasAttribute('v-model')) {
        const vmKey = child.getAttribute('v-model').trim();
        const value = getValue(vmKey, vm);
        child.value = value;
        child.addEventListener('input', () => {
          const keyArr = vmKey.split('.')
          const obj = keyArr.slice(0, keyArr.length - 1).reduce((newObj, k) => newObj[k], vm)
          const leafKey = keyArr[keyArr.length - 1]
          obj[leafKey] = child.value;
        })
      }
      // 元素節(jié)點(diǎn)
      compiler(child, vm)
    } else if (child.nodeType === 3) {
      // 文本節(jié)點(diǎn)
      compilerText(child, vm)
    }
  })
}

export function compilerText (node, vm) {
  if(!node.expr) {
    node.expr = node.textContent; // 把{{ message }} 保存,防止改變數(shù)據(jù)的時(shí)候匹配不到
  }
  node.textContent = node.expr.replace(reg, function(...args){
  // ['{{ message }}', ' message ', 5, '\n    {{ message }}\n    ']
    let key = trimSpace(args[1])
    return JSON.stringify(getValue(key,vm)) 
  })
}

export function getValue(expr,vm) {
  // obj.a
  let keys = expr.split('.');
  return keys.reduce((prevValue, curValue) => {
    prevValue = prevValue[curValue]
    return prevValue
  }, vm);
}

// 去掉空格
export function trimSpace(str) {
  return str.replace(/\s+/g, '')
}
  • 對(duì)節(jié)點(diǎn)進(jìn)行循環(huán)處理,發(fā)現(xiàn)文本節(jié)點(diǎn),進(jìn)行差值表達(dá)式的替換,通過reduce完成鏈?zhǔn)饺≈担瑢⒉逯堤鎿Q成真正的值
  • 發(fā)現(xiàn)元素節(jié)點(diǎn),看節(jié)點(diǎn)上是否存在v-model屬性,獲取到v-model綁定的鍵值,賦值給input節(jié)點(diǎn),并且監(jiān)聽該節(jié)點(diǎn)的input事件,將改變的值重新復(fù)制給數(shù)據(jù),賦值的過程,又會(huì)觸發(fā)dep.notify,實(shí)現(xiàn)了視圖的改變影響數(shù)據(jù)的改變。

vue2雙向數(shù)據(jù)綁定基本原理文章來源地址http://www.zghlxwxcb.cn/news/detail-409466.html

到了這里,關(guān)于vue2雙向數(shù)據(jù)綁定基本原理的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Vue雙向數(shù)據(jù)綁定原理(面試必問)

    Vue雙向數(shù)據(jù)綁定原理(面試必問)

    1、前端面試題庫 ( 面試必備) ? ? ? ? ? ? 推薦:★★★★★ 地址:前端面試題庫 ? vue.js是采用數(shù)據(jù)劫持結(jié)合發(fā)布者-訂閱者模式的方式,通過Object.defineProperty()來劫持各個(gè)屬性的setter,getter,在數(shù)據(jù)變動(dòng)時(shí)發(fā)布消息給訂閱者,觸發(fā)相應(yīng)的監(jiān)聽回調(diào)來渲染視圖。 具體步驟

    2023年04月08日
    瀏覽(18)
  • 前端開發(fā),Vue的雙向數(shù)據(jù)綁定的原理

    前端開發(fā),Vue的雙向數(shù)據(jù)綁定的原理

    目錄 一、什么是前端 二、Vue.JS框架 三、雙向數(shù)據(jù)綁定 四、Vue的雙向數(shù)據(jù)綁定的原理 前端通常指的是網(wǎng)頁或應(yīng)用程序中用戶直接交互和感知的部分,也稱為客戶端。前端開發(fā)涉及使用HTML、CSS和JavaScript等技術(shù)來構(gòu)建用戶界面和交互功能。前端開發(fā)人員負(fù)責(zé)確保網(wǎng)站或應(yīng)用程序

    2024年02月19日
    瀏覽(17)
  • 【Vue3】2-10 : 表單處理與雙向數(shù)據(jù)綁定原理

    【Vue3】2-10 : 表單處理與雙向數(shù)據(jù)綁定原理

    一、表單處理 1.1、【雙向綁定】實(shí)現(xiàn)方式一:v-model >??代碼? >? 效果? 1.2、【雙向綁定】實(shí)現(xiàn)方式二::value屬性 + input事件 >??代碼? >? 效果?(同上) 二、實(shí)戰(zhàn) 2.1 【v-model 示例】輸入框? >??代碼 +?效果 (見1.1) 2.2 【v-model 示例】單選框? >??代碼? >? 效果 2

    2024年01月20日
    瀏覽(30)
  • react和vue2/3父子組件的雙向綁定

    react和vue2/3父子組件的雙向綁定

    目錄 Vue3 父子傳值:props(attrs)/emit 父傳子 props 父child :屬性名=\\\"變量\\\" 子props=defineProps({屬性名:type...}) attrs父作用域(除 class、 style 、?props?)屬性集合 父child :屬性名=\\\"變量\\\",屬性名=\\\"常量\\\" 子?attrs = useAttrs() 子傳父emits+@=v-on: 父child @事件名\\\"=\\\"parentClick\\\",parentClick(msg) 子emi

    2024年02月16日
    瀏覽(29)
  • 在vue2使用v-model對(duì)組件進(jìn)行雙向綁定

    v-model=“visible” 等價(jià)于 :value=“visible” 加上 @input=“visible = $event” 所以 v-model 就是父組件向子組件傳了個(gè) value 字段的值,子組件使用 props 定義 value 字段, 就可以在子組件使用 value 讀取這個(gè)值;子組件使用 $emit(‘input’,值) 就可以改變 v-model 的值 父組件 子組件 父組件 子

    2024年02月10日
    瀏覽(17)
  • Vue雙向綁定的原理是什么?

    在 Vue 中,雙向綁定是指數(shù)據(jù)的變化會(huì)同時(shí)反映在視圖上,而視圖的變化也會(huì)同步更新數(shù)據(jù)。Vue 的雙向綁定是通過以下原理實(shí)現(xiàn)的: 數(shù)據(jù)響應(yīng)系統(tǒng)(Reactivity System):Vue 使用了響應(yīng)式的數(shù)據(jù)綁定機(jī)制。當(dāng)你在 Vue 實(shí)例中的數(shù)據(jù)屬性上使用 data 選項(xiàng)定義數(shù)據(jù)時(shí),Vue 會(huì)通過 Obje

    2024年02月08日
    瀏覽(21)
  • angular 雙向數(shù)據(jù)綁定原理

    Angular的雙向數(shù)據(jù)綁定基于Observable和Zone.js實(shí)現(xiàn)。 當(dāng)一個(gè)組件中的屬性或者模板中的表達(dá)式發(fā)生變化時(shí),Angular會(huì)創(chuàng)建一個(gè)變更檢測(cè)器,并且在組件的變更檢測(cè)樹中遍歷所有的子組件和指令,檢測(cè)它們的屬性是否也發(fā)生了變化。如果發(fā)生了變化,那么Angular會(huì)通過變更檢測(cè)器更新

    2024年02月10日
    瀏覽(17)
  • Angular 使用教程——基本語法和雙向數(shù)據(jù)綁定

    Angular 使用教程——基本語法和雙向數(shù)據(jù)綁定

    Angular 是一個(gè)應(yīng)用設(shè)計(jì)框架與開發(fā)平臺(tái),旨在創(chuàng)建高效而精致的單頁面應(yīng)用 Angular 是一個(gè)基于 TypeScript 構(gòu)建的開發(fā)平臺(tái)。它包括:一個(gè)基于組件的框架,用于構(gòu)建可伸縮的 Web 應(yīng)用,一組完美集成的庫,涵蓋各種功能,包括路由、表單管理、客戶端-服務(wù)器通信等,一套開發(fā)工

    2024年02月05日
    瀏覽(20)
  • Vue父子組件間數(shù)據(jù)的雙向綁定

    Vue父子組件間數(shù)據(jù)的雙向綁定

    在vue中數(shù)據(jù)的流向通常是單向的,但是實(shí)際開發(fā)中,存在子組件對(duì)父組件值進(jìn)行更新的情況,例如對(duì)表單組件進(jìn)行二次封裝等,父組件需要響應(yīng)子組件的變化。雙向綁定呼之欲出,vue提供了兩種方法進(jìn)行雙向綁定: 在父組件上 v-model 會(huì)利用子組件名為 value 的 prop 和名為 inp

    2024年02月06日
    瀏覽(25)
  • 【Vue3 知識(shí)第四講】數(shù)據(jù)雙向綁定、事件綁定、事件修飾符詳解

    【Vue3 知識(shí)第四講】數(shù)據(jù)雙向綁定、事件綁定、事件修飾符詳解

    什么是數(shù)據(jù)雙向綁定? 當(dāng)數(shù)據(jù)發(fā)生變化的時(shí)候,視圖會(huì)相應(yīng)的發(fā)生變化 當(dāng)視圖發(fā)生改變的時(shí)候,數(shù)據(jù)也會(huì)相應(yīng)的同步變化 數(shù)字化管理平臺(tái) Vue3+Vite+VueRouter+Pinia+Axios+ElementPlus 權(quán)限系統(tǒng)-商城 個(gè)人博客地址 雙向綁定的指令 ? v-model 指令實(shí)現(xiàn)數(shù)據(jù)雙向綁定 雙向綁定使用場(chǎng)景 ?

    2024年02月09日
    瀏覽(18)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包