一.组件?
1.组件 (Component) 是 Vue.js 最强大的功能之一
2.组件可以扩展 HTML 元素,封装可重用的代码
3.组件是自定义元素
二.使用组件
Vue组件的使用有2个步骤,注册组件,使用组件2个方面
1.注册
要注册一个全局组件,你可以使用 Vue.component(tagName, options)
。例如:
Vue.component('my-component', {
template: '<div>A custom component!</div>'
})
注意:
① Vue.component(tagName, options)//注册全局组件: (组件名称 组件构造器)
组件构造器:
//创建一个组件构造器
var myComponent = Vue.extend({
template:'<div>A custom component!</div>'
})
Vue.component('my-component',myComponent)
②对于自定义标签名,小写并且包含一个短杠,尽管遵循这个规则比较好。
2.实例化
new Vue({
el: '#app'
})
三.动态组件,is,keep-alive,异步组件
1.动态组件
什么是动态组件:就是几个组件放在一个挂载点下,然后根据父组件的某个变量来决定显示哪个,或者都不显示。
动态切换:(:is后面的是对应的组件名,是变量,必须一致)
在挂载点使用component标签,然后使用v-bind:is**=”组件名”**,会自动去找匹配的组件名,如果没有,则不显示;
改变挂载的组件,只需要修改is指令的值即可
<keep-alive>
<component :is="componentID"></component>
</keep-alive>
2.keep-alive
a、包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们
b、它自身不会渲染一个 DOM 元素,也不会出现在父组件链中
c、当组件在 <keep-alive’> 内切换时,它的 activated 和 deactivated 两个生命周期钩子会对应执
keep-alive:
使用 is 特性来切换不同的组件, 会导致重复渲染影响性能, <keep-alive’>能够使组件实例在创建时被缓存
/* 反复切换回影响性能 */
<component :is="currentTabComponent"></component>
/* 未被激活的组件将会被缓存 */
<keep-alive>
<component :is="currentTabComponent"></component>
</keep-alive>
include 和 exclude 属性允许组件有条件地缓存
<!-- 逗号分隔字符串 -->
<keep-alive include="a,b">
<component :is="view"></component>
</keep-alive>
<!-- 正则表达式 (使用 `v-bind`) -->
<keep-alive :include="/a|b/">
<component :is="view"></component>
</keep-alive>
<!-- 数组 (使用 `v-bind`) -->
<keep-alive :include="['a', 'b']">
<component :is="view"></component>
</keep-alive>
max:
最多缓存多少组件实例,一旦数字达到,新实例被创建之前,缓存组件中最久没有被访问实例会被销毁
<keep-alive :max="10"> /* 必须 v-bind 绑定 这样才是 JS 表达式 */
<component :is="view"></component>
</keep-alive>
3.异步组件
只在需要时才从服务器加载模块,且会把结果缓存供未来重新渲染
以工厂函数的方式定义组件,resolve()表示加载成功, reject()表示加载失败
简单的理解:用到的时候加载,不用的时候不加载
Vue.component('async-example', function (resolve, reject) {
setTimeout(() => {
return resolve({template: '<div>I am async!</div>'})
}, 1000)
})
工厂函数也可以返回一个 Promise
Vue.component(
'async-webpack-example',
() => import('./my-async-component') /* import 函数返回一个 Promise 对象 */
)
使用局部注册的时候,可以直接返回 Promise 函数
new Vue({
components: {
'my-component': () => import('./my-async-component')
}
})
路由的懒加载,就是加载异步组件
components: {
Login: () => import('./components/Login'),
Register: () => import('./components/Register')
}
四.functional 函数式组件
<heading :level="1" icon="HOMEMESSAGE">
<a :title="title">{{title}}</a>
</heading>
Vue.component('heading', {
functional: true, //标记函数式组件
props: ['level', 'title', 'icon'],
render(h, context) {
// 函数式组件 没有this,只有上下文context
//子组件节点
let children = [];
// 属性获取
const { icon, title, level } = context.props;
// 添加图标功能 // <svg><use xlink:use="#icon-xxx"></use></svg>
if (icon) {
children.push(h('svg', { class: 'icon' }, [h('use', { attrs: { 'xlink:href': '#icon-' + icon } })]))
}
let vnode = h(
'h' + level,
{ attrs: { title } }, // 之前省略了title的处理
children = children.concat(context.children)// 子组件节点
)
return vnode;
}
})
五.总结Vue组件化的理解
1.vue 组件化理解
定义:组件是可复用的 Vue 实例,准确讲它们是VueComponent的实例,继承自Vue。
优点:从上面案例可以看出组件化可以增加代码的复用性、可维护性和可测试性。
使用场景:什么时候使用组件?以下分类可作为参考:
通用组件:实现最基本的功能,具有通用性、复用性,例如按钮组件、输入框组件、布局组件等。
业务组件:它们完成具体业务,具有一定的复用性,例如登录组件、轮播图组件。
页面组件:组织应用各部分独立内容,需要时在不同页面组件间切换,例如列表页、详情页组件
2.如何使用组件
定义:Vue.component(),components选项,sfc
分类:有状态组件,functional,abstract
有状态组件是组件有data的定义,
functional :可以理解是无状态组件,就没有定义data。是一个函数
abstract:抽象式组件 (放抖动,节流的组件,没具体的视图)
通信:props,$emit()/$on(),provide/inject,$children/$parent/$root/$attrs/$listeners
内容分发:<slot>,<template>,v-slot
使用及优化:is,keep-alive,异步组件
3.vue中的组件经历如下过程
组件配置 => VueComponent实例 => render() => Virtual DOM=> DOM
所以组件的本质是产生虚拟DOM
六.组件或元素引用
<input type="text" ... ref="inp">
mounted(){
// mounted之后才能访问到inp
this.$refs.inp.focus()
}
2.改造message组件用打开、关闭方法控制显示
<!--自定义组件引用-->
<message ref="msg">新增课程成功!</message>
<script>
Vue.component('message', {
// 组件显示状态
data() {
return {
show: false
}
},
template: ` <div class="message-box" v-if="show">
<slot></slot>
<!--toggle内部修改显示状态-->
<span class="message-box-close" @click="toggle">X</span>
</div> `,
// 增加toggle方法维护toggle状态
methods: {
toggle() {
this.show = !this.show;
}
},
// 修改message-close回调为toggle
mounted () {
this.$bus.$on('message-close', this.toggle);
},
})
const app = new Vue({
methods: {
addCourse() {
// 使用$refs.msg访问自定义组件
this.$refs.msg.toggle()
}
}
})
</script>
七.简单的例子
使用Vue,必须要引用它的js:import Vue from 'vue';
1.全局组件
<template>
<div id="app">
<h1>{{title}}</h1>
<my-component></my-component>
</div>
</template>
<script>
import Vue from 'vue';
Vue.component('my-component', {
template: '<div>A custom component!</div>'
})
export default {
name: 'app',
data: function () {
return {
title: '全局组件的使用'
}
}
}
</script>
2.局部组件
<template>
<div id="app">
<h1>{{title}}</h1>
<my-component></my-component>
</div>
</template>
<script>
var Child = {
template: '<div>A custom component!</div>'
}
export default {
name: 'app',
data: function () {
return {
title: '局部组件的使用'
}
},
components: {'my-component': Child}
}
</script>
3.data传值(必须是函数)
<template>
<div id="app">
<h1>{{title}}</h1>
<my-component></my-component>
<my-component></my-component>
<my-component></my-component>
</div>
</template>
<script>
import Vue from 'vue';
var data = { counter: 0 }
Vue.component('my-component', {
template: '<button v-on:click="counter += 1">{{ counter }}</button>',
// 技术上 data 的确是一个函数了,因此 Vue 不会警告,
// 但是我们返回给每个组件的实例的却引用了同一个data对象
data: function () {
return {
counter: 0
}
}
})
export default {
name: 'app',
data: function () {
return {
title: '组件共享了同一个 data,增加一个counter不会影响其他组件'
}
}
}
</script>
四.定制组件的 v-model
一个组件的 v-model 会使用 value 属性和 input 事件,但是诸如单选框、复选框之类的输入类型可能把 value 属性用作了别的目的,model 选项可以回避这样的冲突:
Vue.component('my-checkbox', {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: Boolean,
// this allows using the `value` prop for a different purpose
value: String
},
// ...
})
<my-checkbox v-model="foo" value="some value"></my-checkbox>
上述代码等价于:
<my-checkbox
:checked="foo"
@change="val => { foo = val }"
value="some value">
</my-checkbox>