ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[Vue深入组件-边界情况处理] 访问元素 & 组件

2021-09-08 01:31:54  阅读:182  来源: 互联网

标签:Vue 边界 parent 访问 实例 组件 ref


目录

1. vm.$root

1.1 描述

当前组件树的根 Vue 实例。如果当前实例没有父实例,此实例将会是其自己。

在Vue 中, 什么是一个组件树的根实例? 实际上,通过Vue Devtools 能够很清楚的看到:
image-20210906232341442

具体的,在代码中,Vue 项目的入口文件main.js 中,一般的会有这样的代码段:

new Vue({
  router,
  store,
  render: (h) => h(App),
}).$mount("#app");

创建了一个Vue实例,并塞入了一些东西后,通过$mount 挂载到了#app 这个dom节点。

实际上,和我们常用的组件化开发一样,我们也能在创建组件时(即便是根组件),也能够通过一个个工厂函数的形式,定义一些数据作为这个组件的动态属性值。 例如:

new Vue({
  data() {
    return {
      name: "$root",
    };
  },
  router,
  store,
  render: (h) => h(App),
}).$mount("#app");

这样,你便能够在全局范围内,在组件树的任何一个节点,通过vm.$root 获取到这个根实例,也就能以vm.$root.name 的形式访问到我们定义的name 属性。

1.2 能力

我们可以发现,这点很像一个中央数据管理对象, 类似localStorage,或者更加类似于store,或者Vuex。 没错,只是取决于项目的复杂度考虑,通常不会这样去使用。 但是如果项目本身比较小,而无需引入Vuex 的情况下。 我们可以考虑这样去实现需求。

并且 ,由于data 对象中的所有的 property 都会被加入到 Vue 的响应式系统中, 这意味着,这个值的变化将会引起所有引用处的dom渲染更新。 即:

<!--组件树中的任意组件a-->
vm.$root.name = "update name value!"
<!--组件树中的任意组件b-->
<template>
	{{$root.name}}
</template>

只要在组件树中,任意组件a中去修改name值,其他任意引用的组件都会自动更新。

2. $parent$children

2.1 描述

$parent 指代父实例,如果当前实例有的话。

$children指代子实例,如果当前实例有的话。

所不同的是,也值得注意的是这二者的类型不同,$children 的类型是 Array<Vue instance> , 而 $parent 的类型是 Vue instance

一个组件可以有多个子组件,因此 $children 的类型是 Array<Vue instance> , 这是易于理解的,但是,为什么 $parent 的类型是 Vue instance 而不是 Array<Vue instance> 呢?

一个组件不是也可以被多个组件引用吗? 那父组件不是也应该有多个吗?,如果我们画一个图来理解:

image-20210907001711604

其实,这个原因,文档中早有提及:

注意当点击按钮时,每个组件都会各自独立维护它的 count。因为你每用一次组件,就会有一个它的新实例被创建。link

组件被复用时,为了不会相互影响,Vue 实际上在背后为我们创建了一个全新的实例。

以下是一个验证demo:

image-20210907004800746

2.2 能力

通过这两个属性,我们能够在两个嵌套关系的组件中,轻松的从子组件访问父组件实例,或者从父组件访问子组件实例。

3. 通过$ref 访问子组件实例或者元素

3.1描述:

通过ref 给一个子组件标记一个"id", 然后当子组件挂载后,便可以通过$ref.refname 的形式访问到对应的子组件实例。

在项目开发中,这是一个常使用的子组件实例访问方式。

以下是一个使用示例。

image-20210908000234163

3.2 能力

通过$refs ,vue又给了我们一种访问组件实例的能力,在一定场景下灵活运用,能极大的方便我们的开发过程。

3.3 注意点

  1. 要注意使用的所在生命周期

    在使用ref这种方式时,你特别需要注意的是,你仅能在该组件挂载完毕后才能访问到该组件实例,所有在使用时,你需要确保组件已经挂载的情况下,再使用。

    一般来说,父子组件的createdmounted 声明周期通常是这样的:
    父组件 created --> 子组件 created --> 子组件 mounted --> 父组件mounted

    这意味着,如果你不加以注意的在父组件的created 声明周期钩子种去通过ref 访问子组件实例,是不会成功的:

    image-20210908001206560

    如果你尝试通过ref 访问一个根元素上有v-if 的组件元素,通常是会遇到一些问题的。 因为一些场景下,v-if 的接入会导致上面提到的常规父子生命周期钩子的执行顺序失常。 为了解决该问题,通常你可以利用$nextTick

  2. 不要依赖ref实现响应式

    $refs 只会在组件渲染完成之后生效,并且它们不是响应式的。这仅作为一个用于直接操作子组件的“逃生舱”——你应该避免在模板或计算属性中访问 $refs

    例如,这样是不能预期运行的:

    image-20210908002756585

4. 依赖注入

4.1 描述

假如,有一个多级嵌套的组件,而你需要在最内部去调用最外层组件的方法,你会怎么办? 先不考虑这样的组件是否合适,也不考虑更好的抽离方法。

那么,首先容易想到的是,我们首先要获取到这个最外层的组件的实例,才能去调用最外层组件中methods 对象中定义的方法。

前面我们刚提到过$parent可以获取到父组件的实例。 那么如果层级比较浅还好,我们通过 this.$parent.$parent.....xxxfunc() 这样的"链式访问"就能达到目的了。

但是显然,这是不利于维护的。 也是不太聪明的。

因为一旦你中间需要多嵌套一级组件,那么你就需要对刚才的”链式访问加一个$parent“。

为了说的更加清楚,我们写一个简单的demo复现一下这种场景:
image-20210908010213289

简单说明一下,在index.vue中,我们引入了LevelTwoLevelThree 两个组件,并且写作了嵌套的形式。

之所以能写作嵌套的形式,是利用了<slot> ,如果你对这里不太清楚,请回顾前面的插槽内容。这里只提一点:
如果LevelTwo 组件定义中,没有包含一个 <slot> 元素,则该组件<LevelTwo>起始标签和</LevelTwo>结束标签之间的任何内容都会被抛弃。

这样,就构成了一个三级嵌套的组件层级关系。即:

<index>
	└── <LevelTwo>
   			 └── <LevelThree>

那么,我们在<LevelTwo> 中去调用时,就是这样去调用的:

this.$parent.indexFunc();

同理,在<LevelThree>,是这样调用的:

this.$parent.$parent.indexFunc();

如果,嵌套层级更深会很不方便,且一旦有层级上的改动,这里都要动。

4.2 通过依赖注入,解决特定场景下的问题

首先,这种场景并不常见。 因为一般有公共方法,我们第一想法应该是把它抽离出去。然后在需要使用的地方去引入。那么这里vue,也为这种特定场景,提供了解决方案,那就是 依赖注入。

其实,易于理解,我们把子组件中可能用到的方法,通过某种方式给他"注册"一下。

然后在需要用到该方法的子组件中,去"引入"一下。

我们直接通过示例认识一下用法:

image-20210908010446034

【简单描述】:

Vue 为我们提供两个新的实例选项:provideinject

provide 选项允许我们指定我们想要提供给后代组件的数据/方法。也就是我们刚才提到的"注册"

provide: function() {
    return {
        indexFunc: this.indexFunc,
    };
},

然后在需要用到的所有子组件中,通过inject "注入" provide 的数据/方法, 也就是我们刚才提到的"引入"

最后,直接通过this.indexFunc() 就可以成功调用了。

这就是依赖注入。

vue 文档上用的示例是google map , 对国内用户确实不太友好,因为假如你想写个google map 的demo , 你还得搞到google map 开发的key才行 - -

标签:Vue,边界,parent,访问,实例,组件,ref
来源: https://www.cnblogs.com/jaycethanks/p/15240891.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有