Vue 官方文档学习笔记(二)深入了解组件

组件注册
一、组件名
1、注册组件时,需要给组件定义名称,以便后续使用。在W3C规范中,自定义组件名时 字母全小写其必须包含一个连字符。可以避免与当前及未来的HTML元素冲突(除了在字符串模板或单文件组件);
2、组件名大小写:定义组件名的方式有两种:
1)kebab-case:当使用该方式定义组件名时,必须在引用这个自定义元素时使用 kebab-case;
2)PascalCase:在使用该方法定义组件名时,在引用自定义元素时两种命名法都可以使用。但直接在DOM(即非字符串模板)中使用时只有kebab-case 是有效的;
二、 全局注册
1、可以通过 Vue.component()方法来创建全局注册的组件。全局注册的组件,可以在其注册后用在新创建的Vue根实例(new Vue)的模板中。在所有的子组件中也可以使用;
三、局部注册
1、由于全局注册的组件,在使用像 webpack 这种工程构建系统时,全局注册的组件,即使已经没用作用了,但是它依然会被包含在构建结果中。这就造成了用户下载JavaScript的增加;
2、可以通过一个普通的 JavaScript 对象来定义局部注册的组件,然后在 Vue 实例的 components选项中定义想要使用的局部注册组件;
1)对于 components 对象中的每个 property 来说,其 property 名就是自定义元素的名,其 property 的值就是这个组件的选项对象;
2)局部注册的组件在其子组件中不可用,需要在子组件的 components 选项中声明;
四、模块系统
1、在模块系统中局部注册
1)在使用类似 babel 和 webpack 的模块系统,推荐创建一个 components 目录。
2)在组件中使用时,先通过 import 引入该局部注册的组件文件,在通过 export.default{} 中的 components 选项去声明要去使用的组件即可;
2、基础组件的自动化全局注册
1)基础组件:即会被多次使用的相对通用的组件(eg:输入框、按钮等);
2)若果使用了 webpack(或基于webpack的Vue.cli 3+),则可以使用 require.context()方法,去全局注册非常通用的基础组件。而全局注册的行为,必须在根Vue实例创建之前发生;

Prop
一、Prop 的大小写(camelCase vs kebab-case)
1、在HTML中 attribute 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当使用 DOM 中的模板时,camelCase 的 prop 名需要使用其等价的 kebab-case 命名;
2、若使用字符串模板,则不存在这个限制;
二、Prop 类型
1、当需要给 prop 指定值的类型时,可以以对象形式列出 prop,这些 property 的名称和值分别是 prop 各自的名称和类型;
2、这样操作即为组件提供了文档,也会在 prop 接收到错误的值的类型时从浏览器的 JavaScript 控制台得到提示;
三、传递静态或动态 Prop
1、可以在元素属性中传递静态的 prop,也可以通过使用 v-bind 动态赋值;实际上任何类型的值都可以传给一个 prop
2、传入一个数字:即使数字是静态的,但是还是需要使用 v-bind 来告诉 Vue 这是一个 JavaScript 表达式,而不是一个字符串;
3、传入一个布尔值:布尔值的传递也需要使用 v-bind 来告诉 Vue 这是一个 JavaScript 表达式;
4、传入一个数组:数组的传递也需要使用 v-bind
5、传入一个对象:对象的传递也需要使用 v-bind
6、传入一个对象的所有 property:此时可以使用不带参数的 v-bind 来直接绑定该对象;
四、单向数据流
1、所有的 prop 都会使其父子 prop 之间形成一个单向下行绑定。这样可以防止子组件意外变更父组件的状态,导致应用的数据流向混乱;
2、每次父级组件发生变更时,子组件中的所有 prop 都将会刷新为最新的值。意味着不能在子组件内部改变 prop,这样会造成警告;
3、两种试图改变 prop 的情况:
1)prop 用来传递一个初始值,子组件将其作为一个本地的 prop 数据来使用:这种情况下,最好定义一个本地的 data property 并将这个 prop 用作初始值;
2)prop 以一种原始的值传入且需要进行转换:这种情况,最好使用这个prop的值来定义一个计算属性;
4、注意:由于在 JavaScript 中,对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中变更这个 prop 将会影响到父组件的状态;
五、Prop 验证
1、可以为组件的 prop 指定验证要求,若未满足要求,Vue会在控制台发出警告;
2、为了定制 prop 的验证方式,可以为 props 中的值提供一个带有验证需求的对象;
3、注意:prop 的验证会在组件实例创建之前进行验证,所以实例的 property(eg:data、computed等)在 defaultvalidator 函数中是不可用的;
4、类型检查:type 可以是 String、Number、Boolean、Array、Object、Data、Function、Symbol 原生构造函数中的一种。也可以是一个自定义的构造函数,并且通过 instanceof 来进行检查确认;
六、非 Prop 的 Attribute
1、一个非 prop 的 attribute 是指传向一个组件,但是该组件并没有相应的 prop 定义的 attribute;
2、显示的定义的 prop 适用于向一个子组件传入信息。但是组件可以接受任意的 attribute,而这些 attribute 会被添加到这个组件的根元素上;
3、替换/合并已有的 Attribute:对于大多数的 attribute 来说,从外部提供给组件的值会替换掉组件内部设置好的值。但 classstyle attribute 会智能的将值合并起来;
4、禁用 Attribute 继承:如果不希望组件的根元素继承 attribute,可以在组件的选项中设置 inheritAttrs: false
1)$sttrs$attrs property 包含了传递给一个组件的 attribute 名和 attribute 值;
2)inheritAttrs:false 与 $attrs 结合使用,可以手动决定这些 attribute 会被赋予哪个元素;
5、注意:inheritAttrs:false 选项不会影响 classstyle 的绑定;
6、该模式允许使用基础组件的时候更像是使用原始的 HTML 元素,而不用担心哪个是真正的根元素;

自定义事件
一、事件名
1、不同于组件和 prop,事件名不存在任何自动化的大小写转化。触发的事件名需要完全匹配监听这个事件所用的名称;
2、不同于组件和 prop,事件名不会被用作一个 JavaScript 变量名或 property 名,所用就不能使用 camelCase 或 PascalCase。且 v-on 事件监听器在 DOM 模板中会被自动转化为全小写,所用最好始终使用 kebab-case 的事件名;
二、自定义组件的 v-model
1、组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但像单选框、复选框等类型的输入控件可能会将 value attribute 用于不同目的。model 选项可以设置该 attribute 作为 prop 时应该使用的类型。且该设置 prop 扔需在组件的 props 选项中声明;
三、将原生事件绑定到组件
1、当需要在一个组件的根元素上直接监听一个原生事件,可以使用 v-on.native 修饰符;
2、当尝试在根元素上去监听一个类似 <input> 的非常特定的元素时,父级的 .native 会失效,虽然不会报错,但是事件处理函数并不会被调用。为此,Vue 提供了一个 $listeners property,它是一个对象,里面包含了作用在这个组件上的所有监听器;
3、可以使用 $listeners property 结合 v-on:“$listeners”将所有的事件监听器指向这个组件的某个特定的子元素。
4、当需要 <input> 配合 v-model 工作时,可以为这些监听器创建一个计算属性,计算属性中合并从父级添加的监听器、在当前元素上自定义的监听器以及组件配合 v-model 的对象合并为一个新的对象返回;
四、.sync 修饰符(2.3.0)
1、在某些情况下,需要对 prop 进行双向数据绑定,但由于真正的双向数据绑定会导致维护上的问题,因为无法确定数据变动的来源。所以 Vue 推荐使用 updata:myPropName 的模式触发事件取而代之。而 Vue 为这种模式提供一个缩写,即 .sync 修饰符;
1)注意,带有 .sync 修饰符的 v-bind 不能和表达式一起使用,只能使用想要绑定的 property 名;
2、当需要用同一个对象设置多个 prop 时,可以将 .sync 结合 v-bind 配合使用,这样会把绑定对象的每一个 property 都作为一个独立的 prop 传进去,然后各自添加用于更新的 v-on 监听器;
1)将 v-bind.sync 用在一个字面量对象上,是无法正常工作的;

插槽
一、插槽内容
1、Vue 官网解释:Vue 实现了一套内容分发的 API,其设计来源于 Web Components 规范草案,并将 <slot> 元素作为承载分发内容的出口;
2、个人理解:在父组件中使用子组件时,在子组件标签中间是不能写任何代码的,即使写了也不会显示。这时,如果父组件在使用子组件时,想要在子组件标签之间加入新的内容(任何内容都可以,html、text、插值表达式),即可在子组件中添加 <slot></slot> 标签去承载这部分代码;
3、插槽存在的意义:我们会把能够复用的代码拆分成一个公用组件,但是这些公用组件在使用的时候并不总能符合所有的使用要求(例如一个按钮的公用组件,在某一处使用时,我们可能会想只是在这一次的使用中为按钮添加一个说明)。此时,则需要在此组件中为这个公用组件添加一个一次性的功能,就可以使用 slot 插槽在公用组件中去承接这部分代码;
4、纵观以上3点,插槽显示的内容将由父组件决定,而插槽显示的位置则由承载的子组件(即上述的公用组件)去决定。而插槽内容显示与否实际则是由父子组件共同决定的;
二、编译作用域
1、实质:由于组件模板的编译都只是在自己的作用域中,所以插槽只能使用自己组件中的数据;
三、后备内容(默认内容)
1、可以在 <slot></slot> 标签中间提供插槽的后备内容,这样当父组件没有内容要显示时,该后备内容将被渲染。但若是父组件提供了插槽内容,则后备内容将被替换;
四、具名插槽(2.6.0以上版本)
1、插槽可以分为:默认插槽和具名插槽两种;
1)默认插槽:即在子组件定义的该插槽默认去承接父组件在使用该子组件时,在子组件标签中间新增的所有内容;
2)具名插槽:此时就是需要子组件中定义多个插槽,去承接父组件中新增的内容。该情况会出现在父组件中想要展示的内容需要在某些特定的位置时;
2、<slot> 元素有一个特殊的 attribute:name 。这个 attribute 可以用来将父组件中定义了 name attribute 的内容对应到子组件的具有相同 name attribute 的 <slot> 元素中;
3、一个不带 name 的 <slot> 出口会有隐含的名字 “default”。即默认插槽;
4、在使用具名插槽时,在父组件中可以在 <template> 元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称。
1)注意:v-slot 指令只能添加到 <template> 元素上。只有在组件中值存在默认插槽时,组件的标签才可以被当做插槽模板使用,此时才可以把 v-slot 直接用在组件上;
5、没有提供 v-slot 指令的内容,将会被视为默认插槽的内容。而该部分内容既可以被显示的包裹在一个定义了指令为 v-slot:default<template> 元素中,也可以不做处理,子组件中的默认插槽会接收余下的所有内容;
五、作用域插槽(2.6.0以上版本)
1、在使用插槽时,插槽能够访问的只有当前组件中的数据。因为插槽实际上就是组件中的 html 模板内容。而模板在编译的时候只能访问当前组件中的数据;
2、当需要在父组件中的插槽内容能够访问到子组件中才有的数据时,可以在子组件的 <slot> 标签中使用 v-bind 去绑定这个数据,绑定在 <slot> 元素上的 attribute 称为插槽 prop。并在父组件中使用带值的 v-slot 来定义提供的插槽 prop 的名字即可;
3、独占默认插槽的缩写语法
1)当被提供的内容只有默认插槽时,组件的标签才可以被当做插槽的模板使用。即可以把 v-slot 直接用在组件上;
2)在只有一个默认插槽时,v-slot 的绑定可以用更简便的写法,即不适用参数,它将被假定对应默认插槽;
3)注意:默认插槽的缩写语法不能和具名插槽混用,会导致作用域不明,报错;
4)只要出现多个插槽,需要始终为所有的插槽使用完整的 <template> 的语法;
4、解构插槽 Prop
1)作用域插槽的内部工作原理是将插槽的内容包括在一个传入单个参数的函数里。那么,v-slot 的值实际上可以是任何能够作为函数定义中的参数的 JavaScript 表达式;
2)在支持的环境下(单文件组件或现代浏览器),可以使用 ES2015 解构来传入具体的插槽 prop。
(1)eg1:单纯的解构 <template v-slot="{ user }">{{user.name}}</template>
(2)eg2:重命名的解构 <template v-slot="{ user:person }">{{person.name}}</template>
(3)eg3:定义后备内容的解构 <template v-slot="{ user ={ name:cooper } }">{{user.name}}</template>
六、动态插槽名(2.6.0)
1、动态指令参数也可以在 v-slot 上使用,用来定义动态插槽名
1)eg:<template v-slot:[userName]></template>
七、具名插槽的缩写(2.6.0)
1、v-slot 也有缩写,即把(v-slot:)替换为 #。而该缩写只有在其有参数的时候才可以使用,否则无效;
八、其他示例
1、插槽 prop 允许我们将插槽转换为可复用的模板,这些模板可以基于输入的 prop 渲染出不同的内容;
2、用处:在设计封装数据逻辑的同时允许父级组件自定义部分布局的可复用组件;
九、废弃了的语法
1、废弃了的语法包括 slotslot-scope attribute。在 2.x版本中依然支持,但在 3.x中将被彻底废弃;
2、即现在由 v-slot 代替原用来绑定具名插槽的 slot attribute 以及原用来绑定作用域插槽的 slot-scope attribute;

动态组件&异步组件
一、在动态组件上使用 keep-alive
1、在多标签页面中可以使用 is attribute 来切换不同的组件,但在组件间切换时,若想保持被切换掉的组件的状态,避免重复渲染而导致的性能问题。可以使用 <keep-alive> 元素将组件包裹起来,使得组件在第一次创建后被缓存起来。这是因为组件在切换时,每次都会创建新的组件实例;
2、注意:在使用 <keep-alive> 时,要求被切换的组件都有自己的名字,不论名字是通过 name 选项韩式局部/全局注册的;
二、异步组件
1、Vue 允许以一个工厂函数的方式定义组件,这个工厂函数会异步解析该组件,Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结构缓存起来供未来重渲染。从而满足组件只有在需要的时候才从服务器加载的需求;
2、该工厂函数会收到一个 resolve 回调,该回调函数会在用户在服务器得到组件的定义时被调用。也可以调用 reject(reason) 来表示加载失败。而如何获取组件则完全取决于用户如何定义。Vue 官方推荐是将异步组件和 webpack 的 code-splitting 功能一起配合使用;
3、可以在工厂函数中返回一个 promise 对象。当使用局部注册时,也可以直接提供一个返回 promise 的函数;
4、处理加载状态(2.3.0):工厂函数可以返回一个指定格式的对象,来指定加载组件的路径,失败时的替换组件,组件加载时的延迟时间等信息;

处理边界情况
一、访问元素&组件
1、在大多数情况下,最好不要触达另一个组件实例内部或手动操作 DOM 元素;但是 Vue 还是提供了相应的方法去处理上述情况;
2、访问根实例
1)在每个 new Vue 实例的子组件中,其根实例可以通过 $root property 进行访问;
2)所有的子组件都可以将这个实例作为一个全局的 store 来访问或使用。这在小型的组件间使用很方便,当在中大型的应用中则推荐使用 vuex 来管理应用状态;
3、访问父级组件实例
1)和 $root 类似,Vue 提供了 $parent property 可以用来从一个子组件访问父组件实例。以替代将数据以 prop 的方式传入子组件中。
2)但是这种方式会使得代码难以调试和理解。因为在后期维护的时候会很难找到变更数据的代码是在父组件还是子组件通过 $parent 更改的;
4、访问子组件实例或子元素
1)尽管 Vue 提供了 prop 和事件来进行父子组件间的数据传递。但是 Vue 还是提供了一个可以在 JavaScript 里直接访问一个子组件的方法。即通过 ref attribute 为子组件赋予一个 ID 引用。在定义了 ref 的组件里,就可以通过 $ref 来访问这个子组件实例;
2)通过使用 $ref 就可以在父组件的方法中直接定义子组件的一些方法;
3)当 refv-for 一起使用时,得到的 ref 将会是一个包含了对应数据源的子组件的数组
4)注意:$ref 只会在组件渲染完成之后生效,并且它不是响应式的。这仅作为一个直接操作子组件的“逃生舱”。应该避免在模板或计算属性中访问 $ref
5、依赖注入
1)由于 $parent property 无法扩展到更深层次的嵌套组件中。为此,Vue 提供了两个新的实例选项:provideinject
2)provide 选项允许指定想要提供给其后代组件的数据/方法;
3)inject 选项,则可以在制定了 provide 的组件的任何后代组件里,来接收指定的 property;
4)provideinject 选项的结合,可以让用户在任意后代组件中访问其父级组件(或更深层次的父级组件)中指定的数据,而不用将整个实例暴露。且这些组件之间的接口是明确定义的,和 prop 一样;
5)实际上,可以把依赖注入看作一部分“大范围有效的 prop”,除了:
(1)祖先组件不需要知道哪些后代组件使用它提供的 property;
(2)后代组件不需要知道被注入的 property 来自哪里;
6)问题:依赖注入将应用程序中的组件与它们当前的组织方式耦合起来,使得重构困难。同时依赖注入提供的 property 是非响应式的;
二、程序化的事件监听器
1、$emit 可以被 v-on 监听。但 Vue 在其事件接口中也提供了其他的方法:
1)通过 $on(eventName, eventHandle) 侦听一个事件;
2)通过 $once(eventName, eventHandle) 一次性侦听一个事件;
3)通过 $off(eventName, eventHandle) 停止侦听一个事件;
2、通常情况下,该方法是用不到的。但是,当需要在一个组件实例上手动侦听事件时,为了解决事件的访问域的问题以及后期清理事件的问题,则需要程序化的事件监听器;
三、循环引用
1、递归组件
1)组件可以通过 name 选项来达到在自己的模板中调用自身;
2)由于递归组件可能会导致无限循环,所以确保在使用递归组件时,是条件性的(例如使用一个最终会得到 false 的 v-if);
2、组件之间的循环引用
1)该问题发生在两个组件互为对方的后代和祖先时。当使用 Vue.component 全局注册组件时,该问题会被 Vue 自动解开。
2)但当使用模块系统依赖/导入组件时(例如 webpack 或 Browserify),则由于组件间的相互依赖导致错误。此时解决的方法则是:将一个组件在生命周期钩子 beforeCreate 时去注册,或是在本地注册组件时,使用 webpack 的异步 import;
四、模板定义的替代品
1、内联模板
1)当 inline-template 这个 attribute 出现在一个子组件上时,这个组件将会使用其里面的内容作为模板,而不是将其作为被分发的内容。内联模板需要定义在 Vue 所属的 DOM 元素内;
2)内联模板会让模板的作用域变得难以理解。所以推荐在组件内优先选择 <template> 选项或 .vue 文件里的一个 <template> 元素来定义模板;
2、x-Template
1)另一个定义模板的的方式是在 <script> 元素中,并为其带上 text/x-template 的类型,然后通过一个 id 将模板引用过去。x-template 需要定义在 Vue 所属的 DOM 元素内;
2)该方式适用于模板特别大的 demo 或极小的应用,其他情况下应避免使用,因为这会将模板和该组件的其它定义分离开;
五、控制更新
1、强制更新:可以通过使用 $forceUpdata 来手动强制更新
2、通过 v-once 创建低开销的静态组件:首先,渲染普通的 HTML 元素在 Vue 中是非常快速的,但是在一个包含大量的静态内容的组件中的根元素上使用 v-once 可以确保这些内容只计算一次然后缓存起来。此时的组件将不在更新;

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值