组件部分
组件注册
-
组件名的大小写问题
定义组件名的方式有两种:
使用kebab-case ==>
Vue.component('my-component-name', { /* ... */ }),在使用短横线分隔命名定义组件时,引用这个自定义组件也必须使用kebab-case的形式使用PascalCase =>
Vue.component('MyComponentName', { /* ... */ }),在使用首字母大写命名定义组件时,在引用这个自定义组件时,两种形式都可以使用注意: 直接在 DOM(即非字符串的模板)中使用时只有
kebab-case是有效的 -
在模块系统中局部注册注意点
如果在使用诸如 Babel 和 webpack 的模块系统,推荐创建一个
components目录来存放组件
Prop
-
Prop 传值注意事项
如果 prop 传递的是一个静态的字符串值,那么可以直接使用
title="My journey with Vue"的形式来传递这个字符串值如果 prop 传递的是动态参数、数字、布尔值等等非字符串值,那么必须要通过
v-bind进行动态的赋值如果 prop 想要将一个对象的所有属性都传入,可以直接使用不带参数的
v-bind进行传入 -
单向数据流
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 能影响子组件,但是子组件不能影响父级组件的状态
不应该在子组件内部改变 prop,有两种常见的变更 prop 的方式:
-
这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用,这个情况下可以使用一个本地的 data property 来接收 prop 用作其初始值
-
这个 prop 以一种原始的值传入且需要进行转换,这个情况下可以使用这个 prop 来定义一个计算属性供子组件进行修改使用
-
-
Prop 验证
prop 会在一个组件实例创建之前进行验证,所以实例的 property(如
data,computed等)在default或validator函数中是不可用的 -
类型检查重点
type可以是String、Number、Boolean、Array、Object、Date、Function、Symbol这八个原生构造函数中的一个也可以是一个自定义的构造函数,并且通过
instanceof来进行检查确认 -
替换/合并已有的 Attribute 注意点
class和style属性值会将值合并起来,但是对于绝大多数 attribute 来说,从外部提供给组件的值会替换掉组件内部设置好的值
自定义事件
-
事件名注意点
事件名不存在任何自动化的大小写转换,因此建议始终使用
kebab-case形式的事件名 -
自定义组件的v-model
组件上的
v-model默认会利用名为value的 prop 和名为input的事件,但是如单选框、复选框等类型的输入控件可能会将value属性用于不同的目的。model选项可以用来避免这样的冲突。Vue.component('base-checkbox', { model: { prop: 'checked', event: 'change' }, props: { checked: Boolean }, template: ` <input type="checkbox" v-bind:checked="checked" v-on:change="$emit('change', $event.target.checked)" > ` }) -
原生事件绑定到组件的注意点
可以使用
v-on的.native修饰符来让一个组件的根元素上直接监听一个原生事件在一些特殊情况,如重构了一个根节点为
label标签的base-input组件时,.native监听器会静默失败,但是不会产生任何报错,但是 原生事件的处理函数可能不会如预期调用,针对这种情况,可以使用$listeners属性来包含作用在这个组件上的所有监听器,它是一个对象,例如{ focus: function (event) { /* ... */ } input: function (value) { /* ... */ }, } -
.sync 修饰符的注意点
.sync是一个语法糖,用于父组件监听子组件更新某个 props 的请求的缩写语法带有
.sync修饰符的v-bind不能和表达式一起使用,而是只能提供想要绑定的属性名将
v-bind.sync用在一个字面量的对象上,是无法正常工作的
插槽
-
插槽语法注意点
自2.6.0开始,Vue为具名插槽和作用域插槽引入了新的统一语法,即
v-slot指令来取代slot和slot-scope这两个已经被废弃但未被移除且仍在文档中的属性 -
插槽使用注意点‘
如果子组件的
template中没有包含任何一个slot元素,那么父组件起始标签和结束标签之间的任何内容都会被抛弃在插槽中使用数据时,如
{{ user.name }},该插槽可以访问实例 property,但不能访问子组件上的属性等,即不能访问子组件的作用域,父级模板里的所有内容都是在父级作用域中编译的,子模板里的所有内容都是在子作用域中编译的 -
具名插槽注意点
可以在
<template>元素上使用v-slot指令,并以v-slot的参数的形式提供其名称(<template v-slot:name>),如:<template v-slot:header> <h1>Here might be a page title</h1> </template>任何没有被包裹在带有
v-slot的template中的内容会被视为默认插槽的内容注意:
v-slot只能添加在<template>上(只有在被提供的内容只有默认插槽时,才可以直接将v-slot用在组件上)v-slot:可以进行缩写,可以替换为字符#,前提是该缩写只有在有参数的情况下才可以使用 -
作用域插槽注意点
作用域插槽的作用为:让父组件的插槽内容能够访问到子组件才有的数据
绑定在
<slot>元素上的 attribute 被称为插槽 prop,如<span> <slot v-bind:user="user"> {{ user.lastName }} </slot> </span>在父组件中可以使用带值的
v-slot来定义子组件提供的插槽 prop 的名字,如<template v-slot:default="slotProps"> {{ slotProps.user.firstName }} </template>注意: 这里的
slotProps可以任意指定 -
解构插槽 prop
作用域插槽的工作原理:将插槽内容包裹在一个拥有单个参数的函数里
因此,
v-slot的值可以是任何能够作为函数定义中的参数的JavaScript表达式,在支持的环境下(单文件组件或现代浏览器),也可以使用ES2015 解构来传入具体的插槽 prop -
其他插槽使用示例
插槽 prop 允许将插槽转换为可复用的模板,这些模板可以基于输入的 prop 渲染出不同的内容,示例如下:
子组件: <ul> <li v-for="todo in filteredTodos" v-bind:key="todo.id" > <!-- 我们为每个 todo 准备了一个插槽, 将 `todo` 对象作为一个插槽的 prop 传入。 --> <slot name="todo" v-bind:todo="todo"> <!-- 后备内容 --> {{ todo.text }} </slot> </li> </ul> 父组件: <todo-list v-bind:todos="todos"> <template v-slot:todo="{ todo }"> <span v-if="todo.isComplete">✓</span> {{ todo.text }} </template> </todo-list>
动态组件&异步组件
-
动态组件注意点
组件在进行切换时,都是一个销毁再创建的过程
如果希望组件在进行切换时,能够在第一次被创建后进行缓存,可以使用
<keep-alive>元素将动态组件包裹起来,如<keep-alive> <component></component> </keep-alive>注意:
<keep-alive>要求被切换的组件都有自己的名字,不管是通过组件的name选项还是局部/全局注册 -
异步组件知识点
Vue 可以通过一个工厂函数的方式定义组件,工厂函数会异步解析组件的定义。 Vue 只有在这个组件需要被渲染的时候才会触发这个工厂函数,并且会把结果缓存起来供未来重渲染,如
Vue.component('async-example', function (resolve, reject) { setTimeout(function () { // 向 `resolve` 回调传递组件定义 re solve({ template: '<div>I am async!</div>' }) }, 1000) })
处理边界情况
-
访问根实例
在每一个
new Vue实例的子组件中,子组件可以通过$root属性来对根组件进行访问 -
**访问父级组件实例
子组件可以通过
$parent来访问父组件的实例注意: 子组件触达父级组件会让应用更难调试和理解,尤其是在变更了父级组件的数据的时候,之后再回看子组件的时候,会很难找到源数据是从哪里来的,所以不推荐这种做法
-
访问子组件实例或子元素
父组件可以通过
$ref属性为子组件赋予一个 ID 的引用使用时可以通过
this.$refs.name来使用这个子组件当
ref和v-for一起使用的时候,父组件得到的 ref 是一个包含了对应数据源的这些子组件的数组注意:
$refs只会在组件渲染完成之后生效,并且它们不是响应式的 -
依赖注入知识点
provide选项可以使父组件指定想要提供给后代组件的数据/方法。provide使用方法如下所示:provide() { return { name: this.name sayHi: this.sayHi } }在任何后代组件(包括深层的后代组件)中,可以使用
inject选项来接收父组件指定的属性/方法可以把依赖注入看作一部分“大范围有效的 prop”,除了:
1. 祖先组件不需要知道哪些后代组件使用了它提供的 property 2. 后代组件不需要知道被注入的 property 来自哪里注意: 这样的方式和使用
$root一样是不够好的,会将应用程序中的组件与它们当前的组织形式耦合起来,换而言之就是在将组件使用到其他地方时,也应该有这样的文件结构,更好的解决方案应用是使用vuex -
程序化的事件侦听器
事件可以被
v-on侦听,$emit可以用来触发事件- 通过
$on(eventName, eventHandler)侦听一个事件 - 通过
$once(eventName, eventHandler)一次性侦听一个事件 - 通过
$off(eventName, eventHandler)停止侦听一个事件
- 通过
-
内联模板知识点
当
inline-template这个属性出现在一个子组件上时,这个组件将会用里面的内容作为模板,而不是将其作为被分发的内容,内联模板需要定义在 Vue 所属的 DOM 元素内注意: 最佳实践是在组件内优先选择
template选项或.vue文件里的template元素来定义模板 -
控制更新知识点
在需要手动强制更新时,可以通过
$forceUpdate来进行操作如果一个组件中包含了大量的静态内容,可以在根元素上添加
v-once属性来确保这些内容只计算一次就被缓存起来