1、组件基础
1.1、复用
组件可被复用,每用一次组件,就会有一个它的新实例被创建。
组件的data必须是一个函数,每个实例可以维护一份被返回对象的独立的拷贝
1.2、注册
为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册和局部注册。
Vue.component:全局注册
1.3、父子组件传值
父 ===》子
Vue.component('blog-post', {
props: ['title'],
template: '<h3>{{ title }}</h3>'
})
//...
<blog-post title="My journey with Vue"></blog-post>
子 ===》父
$emit
<blog-post
...
v-on:enlarge-text="postFontSize += 0.1"
></blog-post>
//...
<button v-on:click="$emit('enlarge-text')">
Enlarge text
</button>
1.4、单个根元素
1.5、在组件上使用v-model
1.6、插槽
<alert-box>
Something bad happened.
</alert-box>
//...
Vue.component('alert-box', {
template: `
<div class="demo-alert-box">
<strong>Error!</strong>
<slot></slot>
</div>
`
})
1.7、动态组件
<!-- 组件会在 `currentTabComponent` 改变时改变 -->
<component v-bind:is="currentTabComponent"></component>
已注册组件的名字,或
一个组件的选项对象
2、注册组件
2.1、命名:
例如<my-component-name>,这个组件名在注册的时候的两种写法:
Vue.component('my-component-name', { /* ... */ })
Vue.component('MyComponentName', { /* ... */ })
2.2、全局注册与局部注册
全局:Vue.component。在注册之后可以用在任何新创建的 Vue 根实例 (new Vue) 的模板中。可以在各自内部互相使用
局部:全局注册所有的组件意味着即便你已经不再使用一个组件了,它仍然会被包含在你最终的构建结果中。这造成了用户下载的 JavaScript 的无谓的增加。
var ComponentA = { /* ... */ }
// ...
new Vue({
el: '#app',
components: {
'component-a': ComponentA, // 对于每个属性来说,属性名是自定义元素名字,属性值是组件的选项对象
'component-b': ComponentB
}
})
或者通过 Babel 和 webpack 使用 ES2015 模块
import ComponentA from './ComponentA.vue'
export default {
components: {
ComponentA // ComponentA: ComponentA 的缩写
},
// ...
}
2.3、模块系统
单独建立一个component目录存放各种模块,在需要用到的时候可以直接import
对于一些基础组件,需要在很多地方引用,可以用到全局注册(全局注册的行为必须在根 Vue 实例 (通过 new Vue) 创建之前发生):
前提:使用了webpack (或在内部使用了 webpack 的 Vue CLI 3+);
方式:在应用入口文件 (比如 src/main.js) 中全局导入基础组件,require.context
例子参见:https://cn.vuejs.org/v2/guide/components-registration.html#%E5%9F%BA%E7%A1%80%E7%BB%84%E4%BB%B6%E7%9A%84%E8%87%AA%E5%8A%A8%E5%8C%96%E5%85%A8%E5%B1%80%E6%B3%A8%E5%86%8C
3、prop(父向子传值)
3.1、命名
Vue.component('blog-post', {
// 在 JavaScript 中是 camelCase 的
props: ['postTitle'],
template: '<h3>{{ postTitle }}</h3>'
})
<!-- 在 HTML 中是 kebab-case 的 -->
<blog-post post-title="hello!"></blog-post> // 父的驼峰式命名在子中要改成短横线分隔命名
3.2、单向数据流
在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变这个对象或数组本身将会影响到父组件的状态。
3.3、prop验证
一个非 prop 的 attribute 是指传向一个组件,但是该组件并没有相应 prop 定义的
attribute。
一种写法,可以在prop中传参,value和type来检测传值的类型等
4、自定义事件
4.1、命名:全为小写(因为v-on 事件监听器在 DOM 模板中会被自动转换为全小写,HTML是大小写不敏感的)
4.2、自定义组件v-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)"
>
`
})
// ...
<base-checkbox v-model="lovingVue"></base-checkbox>
4.3、原生事件绑定到组件
listeners" 将所有的事件监听器指向这个组件的某个特定的子元素。
4.4、.sync 修饰符
5、插槽
5.1、
<navigation-link url="/profile">
Your Profile
</navigation-link>
// ...
<a
v-bind:href="url"
class="nav-link"
>
<slot></slot>
</a>
插槽内可以包含任何的内容
5.2、编译作用域
父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。
5.3、后备内容
<button type="submit">
<slot>Submit</slot>
</button>
5.4、具名插槽
<slot name="header"></slot> //已废弃
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
5.5、作用域插槽
插槽内容能够访问子组件中才有的数据
绑定在 <slot> 元素上的 attribute 被称为插槽 prop
<span>
<slot v-bind:user="user">
{{ user.lastName }}
</slot>
</span>
// ...
<current-user>
<template v-slot:default="slotProps">
{{ slotProps.user.firstName }}
</template>
</current-user>
5.6、具名插槽的缩写
v-slot:header 可以被重写为 #header
<!-- 这样会触发一个警告 -->
<current-user #="{ user }"> //缩写只在其有参数的时候才可用,可以写成#default="{ user }"
{{ user.firstName }}
</current-user>
6、动态组件
<keep-alive>
<!-- 失活的组件将会被缓存!-->
<keep-alive>
<component v-bind:is="currentTabComponent"></component>
</keep-alive>
7、异步组件
在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器加载一个模块。为了简化,Vue 允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义。Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染。
Vue.component('async-webpack-example', function (resolve) {
// 这个特殊的 `require` 语法将会告诉 webpack
// 自动将你的构建代码切割成多个包,这些包
// 会通过 Ajax 请求加载
require(['./my-async-component'], resolve)
})
// ...
const AsyncComponent = () => ({
// 需要加载的组件 (应该是一个 `Promise` 对象)
component: import('./MyComponent.vue'),
// 异步组件加载时使用的组件
loading: LoadingComponent,
// 加载失败时使用的组件
error: ErrorComponent,
// 展示加载时组件的延时时间。默认值是 200 (毫秒)
delay: 200,
// 如果提供了超时时间且组件加载也超时了,
// 则使用加载失败时使用的组件。默认值是:`Infinity`
timeout: 3000
})
8、处理边界情况
触达另一个组件实例内部或手动操作 DOM 元素
8.1、访问父组件的根实例:parent
ref
依赖注入
8.2、程序化事件监听器