亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Vue中v-bind原理深入探究

 更新時(shí)間:2022年10月21日 16:13:23   作者:Young soul2  
這篇文章主要給大家分享了 v-bind的使用和注意需要注意的點(diǎn),下面文章圍繞 v-bind指令的相關(guān)資料展開內(nèi)容且附上詳細(xì)代碼 需要的小伙伴可以參考一下,希望對(duì)大家有所幫助

前面我們分析了v-model的原理,接下來我們看看v-bind的實(shí)現(xiàn)又是怎樣的呢?

前置內(nèi)容

<template>
  <div>
    <test :propTest="a"></test>
    <div @click="changeA">點(diǎn)我</div>
  </div>
</template>
<script>
import test from './test.vue'
export default {
  name: "TestWebpackTest",
  components:{
    test
  },
  mounted() {
    console.log(this);
  },
  methods:{
    changeA(){
      this.a = Math.random()
    }
  },
  data() {
    return {
      a:111,
    };
  }
};
</script>
...
<template>
  <div>
   {{propTest}}
  </div>
</template>
<script>
export default {
  name: 'test',
   mounted() {
    console.log(this);
  },
  props:{
    propTest:Number
  }
}
</script>
<style>
</style>

解析模板

// App.vue
var render = function render() {
  var _vm = this,
    _c = _vm._self._c
  return _c(
    "div",
    [
      _c("test", { attrs: { propTest: _vm.a } }),
      _vm._v(" "),
      _c("div", { on: { click: _vm.changeA } }, [_vm._v("點(diǎn)我")]),
    ],
    1
  )
}

可以看出v-on:propTest='a’會(huì)被解析成attrs: { propTest: _vm.a },看過前幾篇文章的都知道會(huì)觸發(fā)a變量的get方法收集依賴。目前主要是看當(dāng)前組件是怎么把a(bǔ)ttrs屬性傳遞給子組件的:

function createElement$1(context, tag, data, children, normalizationType, alwaysNormalize) {
   if (isArray(data) || isPrimitive(data)) {
       normalizationType = children;
       children = data;
       data = undefined;
   }
   if (isTrue(alwaysNormalize)) {
       normalizationType = ALWAYS_NORMALIZE;
   }
   return _createElement(context, tag, data, children, normalizationType);
}

_c(“test”, { attrs: { propTest: _vm.a } })方法主要執(zhí)行createElement$1方法:

function _createElement(context, tag, data, children, normalizationType) {
 	   ...
       else if ((!data || !data.pre) &&
           isDef((Ctor = resolveAsset(context.$options, 'components', tag)))) {
           // component
           vnode = createComponent(Ctor, data, context, children, tag);
       }
       ...
   if (isArray(vnode)) {
       return vnode;
   }
   else if (isDef(vnode)) {
       if (isDef(ns))
           applyNS(vnode, ns);
       if (isDef(data))
           registerDeepBindings(data);
       return vnode;
   }
   else {
       return createEmptyVNode();
   }
}

主要執(zhí)行createComponent方法,傳入?yún)?shù)如圖所示:

接下來執(zhí)行createComponent函數(shù),并創(chuàng)建test的vm函數(shù)然后創(chuàng)建test的vnode:

function createComponent(Ctor, data, context, children, tag) {
    ...
    var baseCtor = context.$options._base;
    // plain options object: turn it into a constructor
    if (isObject(Ctor)) {
        Ctor = baseCtor.extend(Ctor);
    }
  ...
    data = data || {};
    // resolve constructor options in case global mixins are applied after
    // component constructor creation
    resolveConstructorOptions(Ctor);
    // transform component v-model data into props & events
    if (isDef(data.model)) {
        // @ts-expect-error
        transformModel(Ctor.options, data);
    }
    // extract props
    // @ts-expect-error
    var propsData = extractPropsFromVNodeData(data, Ctor, tag);
    // functional component
    // @ts-expect-error
    if (isTrue(Ctor.options.functional)) {
        return createFunctionalComponent(Ctor, propsData, data, context, children);
    }
    // extract listeners, since these needs to be treated as
    // child component listeners instead of DOM listeners
    var listeners = data.on;
    // replace with listeners with .native modifier
    // so it gets processed during parent component patch.
    data.on = data.nativeOn;
    // @ts-expect-error
    if (isTrue(Ctor.options.abstract)) {
        // abstract components do not keep anything
        // other than props & listeners & slot
        // work around flow
        var slot = data.slot;
        data = {};
        if (slot) {
            data.slot = slot;
        }
    }
    // install component management hooks onto the placeholder node
    installComponentHooks(data);
    // return a placeholder vnode
    // @ts-expect-error
    var name = getComponentName(Ctor.options) || tag;
    var vnode = new VNode(
    // @ts-expect-error
    "vue-component-".concat(Ctor.cid).concat(name ? "-".concat(name) : ''), data, undefined, undefined, undefined, context, 
    // @ts-expect-error
    { Ctor: Ctor, propsData: propsData, listeners: listeners, tag: tag, children: children }, asyncFactory);
    return vnode;
}

創(chuàng)建的vnode如下圖所示,其中componetnOptions是創(chuàng)建vm函數(shù)時(shí)的參數(shù)。這個(gè)在后面實(shí)例化test的vm函數(shù)時(shí)有用

此時(shí)所有vnode基本創(chuàng)建完畢。此時(shí)執(zhí)行vm._update(vm._render(), hydrating)方法,該方法主要執(zhí)行vm.$el = vm._patch_(prevVnode, vnode)方法,該方法執(zhí)行createChildren去遍歷vnode執(zhí)行createElm方法:

function createElm(vnode, insertedVnodeQueue, parentElm, refElm, nested, ownerArray, index) {
   ...
    if (createComponent(vnode, insertedVnodeQueue, parentElm, refElm)) {
        return;
    }
   ...
}

由于第一個(gè)node是test是一個(gè)組件,所有會(huì)執(zhí)行createComponent方法:

function createComponent(vnode, insertedVnodeQueue, parentElm, refElm) {
    var i = vnode.data;
    if (isDef(i)) {
        var isReactivated = isDef(vnode.componentInstance) && i.keepAlive;
        if (isDef((i = i.hook)) && isDef((i = i.init))) {
            i(vnode, false /* hydrating */);
        }
        ...
    }
}
...
init: function (vnode, hydrating) {
 ...
    else {
        var child = (vnode.componentInstance = createComponentInstanceForVnode(vnode, activeInstance));
        child.$mount(hydrating ? vnode.elm : undefined, hydrating);
    }
}

該方法執(zhí)行componentVNodeHooks的init方法的createComponentInstanceForVnode去創(chuàng)建test組件的vm實(shí)例:

function createComponentInstanceForVnode(parent) {
    var options = {
        _isComponent: true,
        _parentVnode: vnode,
        parent: parent
    };
    // check inline-template render functions
    var inlineTemplate = vnode.data.inlineTemplate;
    if (isDef(inlineTemplate)) {
        options.render = inlineTemplate.render;
        options.staticRenderFns = inlineTemplate.staticRenderFns;
    }
    return new vnode.componentOptions.Ctor(options);
}

實(shí)例化過程中使用了vnode過程中創(chuàng)建的vm函數(shù),在實(shí)例化的過程中會(huì)執(zhí)行initInternalComponent函數(shù),該函數(shù)從父vnode的componentOptions中獲取prop數(shù)據(jù):

if (options && options._isComponent) {
   // optimize internal component instantiation
     // since dynamic options merging is pretty slow, and none of the
     // internal component options needs special treatment.
     initInternalComponent(vm, options);
 }

到這里為止從App.vue中的attrs屬性就已經(jīng)傳到test組件上了。initInternalComponent方法執(zhí)行完畢繼續(xù)執(zhí)行initState方法:

function initState(vm) {
   var opts = vm.$options;
   if (opts.props)
       initProps$1(vm, opts.props);
   // Composition API
   initSetup(vm);
   if (opts.methods)
       initMethods(vm, opts.methods);
   if (opts.data) {
       initData(vm);
   }
   else {
       var ob = observe((vm._data = {}));
       ob && ob.vmCount++;
   }
   if (opts.computed)
       initComputed$1(vm, opts.computed);
   if (opts.watch && opts.watch !== nativeWatch) {
       initWatch(vm, opts.watch);
   }
}

首先執(zhí)行initProps$1方法:

function initProps$1(vm, propsOptions) {
   var propsData = vm.$options.propsData || {};
   var props = (vm._props = shallowReactive({}));
   // cache prop keys so that future props updates can iterate using Array
   // instead of dynamic object key enumeration.
   var keys = (vm.$options._propKeys = []);
   var isRoot = !vm.$parent;
   // root instance props should be converted
   if (!isRoot) {
       toggleObserving(false);
   }
   var _loop_1 = function (key) {
       keys.push(key);
       var value = validateProp(key, propsOptions, propsData, vm);
       /* istanbul ignore else */
       {
           var hyphenatedKey = hyphenate(key);
           if (isReservedAttribute(hyphenatedKey) ||
               config.isReservedAttr(hyphenatedKey)) {
               warn$2("\"".concat(hyphenatedKey, "\" is a reserved attribute and cannot be used as component prop."), vm);
           }
           defineReactive(props, key, value, function () {
               if (!isRoot && !isUpdatingChildComponent) {
                   warn$2("Avoid mutating a prop directly since the value will be " +
                       "overwritten whenever the parent component re-renders. " +
                       "Instead, use a data or computed property based on the prop's " +
                       "value. Prop being mutated: \"".concat(key, "\""), vm);
               }
           });
       }
       // static props are already proxied on the component's prototype
       // during Vue.extend(). We only need to proxy props defined at
       // instantiation here.
       if (!(key in vm)) {
           proxy(vm, "_props", key);
       }
   };
   for (var key in propsOptions) {
       _loop_1(key);
   }
   toggleObserving(true);
}

獲取到propsOptions并循環(huán)執(zhí)行_loop_1(key)方法,該方法首先執(zhí)行validateProp方法校驗(yàn)數(shù)據(jù)和我們在test組件中定義的props類型是否相同。然后執(zhí)行defineReactive方法將該prop設(shè)置在vm._props中并設(shè)置get和set。

此時(shí)我們得出一個(gè)結(jié)論,test組件會(huì)先根據(jù)props校驗(yàn)propsData的類型并獲取值,test組件定義的props會(huì)被設(shè)置響應(yīng)式。至此App.vue中的v-on中給的值已經(jīng)被傳到test組件并設(shè)置了初始值。

不難看出,當(dāng)App.vue中的數(shù)據(jù)發(fā)生變化時(shí)會(huì)重新執(zhí)行變量中的watcher的update方法重新將值傳入test組件。由于該組件已經(jīng)創(chuàng)建了會(huì)存在prevVnode值,所以不會(huì)再次創(chuàng)建只會(huì)執(zhí)行vm._patch_(prevVnode, vnode)去更新組件的值:

Vue.prototype._update = function (vnode, hydrating) {
    var vm = this;
    var prevEl = vm.$el;
    var prevVnode = vm._vnode;
    var restoreActiveInstance = setActiveInstance(vm);
    vm._vnode = vnode;
    // Vue.prototype.__patch__ is injected in entry points
    // based on the rendering backend used.
    if (!prevVnode) {
        // initial render
        vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */);
    }
    else {
        // updates
        vm.$el = vm.__patch__(prevVnode, vnode);
    }
    ...
};

至此整個(gè)過程結(jié)束。

總結(jié)

  • 會(huì)將v-on:propTest="a"解析成attrs: { propTest: _vm.a },并在渲染組件test的時(shí)候把該值傳過去。
  • 在實(shí)例化組件的時(shí)候會(huì)根據(jù)props里面創(chuàng)建的值和傳進(jìn)來的值做類型校驗(yàn),然后并設(shè)置響應(yīng)式同時(shí)設(shè)置初始值。
  • 父組件值變化的時(shí)候會(huì)觸發(fā)該變量的set方法父組件執(zhí)行updateChildren方法對(duì)比新舊子組件并更新值。

到此這篇關(guān)于Vue中v-bind原理深入探究的文章就介紹到這了,更多相關(guān)Vue v-bind內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解如何用模塊化的方式寫vuejs

    詳解如何用模塊化的方式寫vuejs

    這篇文章主要介紹了詳解如何用模塊化的方式寫vuejs,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-12-12
  • 這15個(gè)Vue指令,讓你的項(xiàng)目開發(fā)爽到爆

    這15個(gè)Vue指令,讓你的項(xiàng)目開發(fā)爽到爆

    這篇文章主要介紹了這15個(gè)Vue指令,讓你的項(xiàng)目開發(fā)爽到爆,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-10-10
  • vue+tsc+noEmit導(dǎo)致打包報(bào)TS類型錯(cuò)誤問題及解決方法

    vue+tsc+noEmit導(dǎo)致打包報(bào)TS類型錯(cuò)誤問題及解決方法

    當(dāng)我們新建vue3項(xiàng)目,package.json文件會(huì)自動(dòng)給我添加一些配置選項(xiàng),這寫選項(xiàng)基本沒有問題,但是在實(shí)際操作過程中,當(dāng)項(xiàng)目越來越復(fù)雜就會(huì)出現(xiàn)問題,本文給大家分享vue+tsc+noEmit導(dǎo)致打包報(bào)TS類型錯(cuò)誤問題及解決方法,感興趣的朋友一起看看吧
    2023-10-10
  • vue-cli中打包圖片路徑錯(cuò)誤的解決方法

    vue-cli中打包圖片路徑錯(cuò)誤的解決方法

    這篇文章主要介紹了vue-cli中打包圖片路徑錯(cuò)誤的解決方法 ,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • Vue Router動(dòng)態(tài)路由使用方法總結(jié)

    Vue Router動(dòng)態(tài)路由使用方法總結(jié)

    這篇文章主要介紹了Vue Router動(dòng)態(tài)路由使用方法總結(jié),需要的朋友可以參考下
    2023-10-10
  • vue2封裝input組件方式(輸入的雙向綁定)

    vue2封裝input組件方式(輸入的雙向綁定)

    這篇文章主要介紹了vue2封裝input組件方式(輸入的雙向綁定),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。
    2023-04-04
  • vue3之Suspense加載異步數(shù)據(jù)的使用

    vue3之Suspense加載異步數(shù)據(jù)的使用

    本文主要介紹了vue3之Suspense加載異步數(shù)據(jù)的使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • 基于mpvue搭建微信小程序項(xiàng)目框架的教程詳解

    基于mpvue搭建微信小程序項(xiàng)目框架的教程詳解

    mpvue從底層支持 Vue.js 語法和構(gòu)建工具體系,同時(shí)再結(jié)合相關(guān)UI組件庫,便可以高效的實(shí)現(xiàn)小程序開發(fā)。這篇文章主要介紹了基于mpvue搭建小程序項(xiàng)目框架 ,需要的朋友可以參考下
    2019-04-04
  • 淺談Vue.js路由管理器 Vue Router

    淺談Vue.js路由管理器 Vue Router

    這篇文章主要介紹了Vue.js路由管理器 Vue Router,主要介紹的是路由元信息,命名路由以及嵌套路由等使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-08-08
  • vue?cli+axios踩坑記錄+攔截器使用方式,代理跨域proxy

    vue?cli+axios踩坑記錄+攔截器使用方式,代理跨域proxy

    這篇文章主要介紹了vue?cli+axios踩坑記錄+攔截器使用方式,代理跨域proxy,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-04-04

最新評(píng)論