个人blog-1: 拾忆生活
个人blog-2: 极简-拾忆生活
欢迎大家来踩,同步更新
vue–自定义 component 标签
-
先仔细看下components命名规则对比
-
is
关键字<component :is="xxx"></component>
-
ComponentA: ComponentA 的缩写---->ComponentA
-
即这个变量名同时是:
- 用在模板中的自定义元素的名称
- 包含了这个组件选项的变量名
import ComponentA from './ComponentA.vue'
export default {
components: {
ComponentA
},
// ...
}
实例1:
<script type="text/javascript">
var HelloTom = {
data: function(){
return {
msg: 'HelloTom'
}
},
template: '<div>{{msg}}</div>'
};
var HelloJerry = {
data: function(){
return {
msg: 'HelloJerry'
}
},
template: '<div>{{msg}}</div>'
};
var vm = new Vue({
el: '#app',
data: {
},
components: {
'hello-tom': HelloTom,
'hello-jerry': HelloJerry
}
});
</script>
动态组件 & 异步组件
的’is’ 关键字
-
′
i
s
′
关
键
字
\color{red}'is' 关键字
′is′关键字 用来动态切换组件
- 其属性值可以是 值、也可以是 函数
- 绑定key数据,根据key的值不同,调用不同的组件。
例1:
<div id="app">
<component :is="key"></component>
</div>
var componentA = {
template: `<div style="color:red">我是A组件</div>`
}
var componentB = {
template: `<div style="color:blank">我是B组件</div>`
}
var componentC = {
template: `<div style="color:pink">我是C组件</div>`
}
var app = new Vue({
el: '#app',
components: {
"comA": componentA,
"comB": componentB,
"comC": componentC
},
data:{
key:'comB'
}
})
例2:
- 多个组件使用同一个挂载点,并动态切换【动态组件】
<div id="example">
<button @click="change">切换页面</button>
<component :is="currentView"></component>
</div>
var home = {template:'<div>我是主页</div>'};
var post = {template:'<div>我是提交页</div>'};
var archive = {template:'<div>我是存档页</div>'};
new Vue({
el: '#example',
components: {
home,
post,
archive,
},
data:{
index:0,
arr:['home','post','archive'],
},
computed:{
currentView(){
return this.arr[this.index];
}
},
methods:{
change(){
this.index = (++this.index)%3;
}
}
})
例2的另一种实现形式:
- 直接绑定到组件对象上,位于data中,用数组表示
<div id="example">
<button @click="change">切换页面</button>
<component :is="currentView"></component>
</div>
new Vue({
el: '#example',
data:{
index:0,
arr:[
{template:`<div>我是主页</div>`},
{template:`<div>我是提交页</div>`},
{template:`<div>我是存档页</div>`}
],
},
computed:{
currentView(){
return this.arr[this.index];
}
},
methods:{
change(){
this.index = (++this.index)%3;
}
}
})
<keep-alive>
标签
- 包裹动态组件【含is】时,会缓存不活动的组件实例,而不是销毁它们
- 失活的组件将会被缓存!
- 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中
- 和
<transition>
相似
实例1:
- 如果有多个条件性的子元素,
<keep-alive>
要求同时只能有一个子元素被渲染- 子元素home
- 子元素posts
- 子元素archive
<div id="example">
<button @click="change">切换页面</button>
<keep-alive>
<home v-if="index===0"></home>
<posts v-else-if="index===1"></posts>
<archive v-else></archive>
</keep-alive>
</div>
new Vue({
el: '#example',
components:{
home:{template:`<div>我是主页</div>`},
posts:{template:`<div>我是提交页</div>`},
archive:{template:`<div>我是存档页</div>`},
},
data:{
index:0,
},
methods:{
change(){
let len = Object.keys(this.$options.components).length;
this.index = (++this.index) % len;
}
}
})
<keep-alive>
的属性【:include
和 :exclude
】
用法:
- include(包括) 和 exclude (不包括)属性允许组件有条件地缓存。
- 首先检查组件自身的 name 选项,【匹配到后则缓存匹配的值】
- 如果 name 选项不可用,则匹配它的局部注册名称(父组件 components 选项的键值)【匹配到后则缓存匹配的值】
- (使用 v-bind)
<!-- 逗号分隔字符串 -->
<keep-alive include="a,b">
<component :is="view"></component>
</keep-alive>
<!-- 正则表达式 -->
<keep-alive :include="/a|b/">
<component :is="view"></component>
</keep-alive>
<!-- Array -->
<keep-alive :include="['a', 'b']">
<component :is="view"></component>
</keep-alive>
分析:
- 这里是检查了自己的name属性,发现未找到
- 再检查局部注册名称(父组件) components 选项的键值
- 所以【include】只缓存home和archive,不缓存posts
<div id="example">
<button @click="change">切换页面</button>
<keep-alive include="home,archive">
<component :is="currentView"></component>
</keep-alive>
</div>
new Vue({
el: '#example',
data:{
index:0,
arr:[
{name:'home',template:`<div>我是主页</div>`},
{name:'posts',template:`<div>我是提交页</div>`},
{name:'archive',template:`<div>我是存档页</div>`}
],
},
computed:{
currentView(){
return this.arr[this.index];
}
},
methods:{
change(){
var len = this.arr.length;
this.index = (++this.index)% len;
},
}
})
<keep-alive>
的【activated()
和 deactivated()
】函数
用法:
- 在
<keep-alive>
树内的所有嵌套组件中触发- activated() 点击开始时
- deactivated() 切换结束时
分析:
- :is=“currentView”,函数在计算属性中定义
- data的arr中存放模板
- 注意:【activated()和deactivated()中的重写
$emit
函数,是vue自定义事件pass-data】
- 注意:【activated()和deactivated()中的重写
- 当按顺序点击,轮到下标是 我是主页 的模板是触发自定义函数
@pass-data,其参数则触发getData延迟(先显示$emit的第二个参数值,再消失"")
<div id="example">
<button @click="change">切换页面</button>
<keep-alive>
<component :is="currentView" @pass-data="getData"></component>
</keep-alive>
<p>{{msg}}</p>
</div>
new Vue({
el: '#example',
data:{
index:0,
msg:'',
arr:[
{
template:`<div>我是主页</div>`,
activated(){
this.$emit('pass-data','主页被添加');
},
deactivated(){
this.$emit('pass-data','主页被移除');
},
},
{template:`<div>我是提交页</div>`},
{template:`<div>我是存档页</div>`}
],
},
computed:{
currentView(){
return this.arr[this.index];
}
},
methods:{
change(){
var len = this.arr.length;
this.index = (++this.index)% len;
},
getData(value){
this.msg = value;
setTimeout(()=>{
this.msg = '';
},500)
}
}
})
异步组件
- 以一个工厂函数的方式定义你的组件,它会异步解析你的组件定义
- 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染
核心:
- 是第二个参数
function (resolve, reject) {...}
实现:
- resolve加载成功后,执行处理的逻辑
- reject加载失败后,执行处理的逻辑
普通组件:
Vue.component('async-example', {
template: `<div>this is a global component</div>`
})
异步组件:
Vue.component('async-example', function (resolve, reject) {
// do some thing 处理其它逻辑,并在完成后向 `resolve` 回调传递组件定义
resolve({
template: '<div>I am async!</div>'
// 组件定义的其它选项
})
// 或者调用reject回调表示失败
reject({
template: `<div>result is failed</div>`
})
})
异步组件变成单文件.vue
+ webpack 的 code-splitting
【定义为异步加载的组件,在打包时,打包成单独js文件存储在static/js文件夹】
require
my-async-component.vue【变成单组件】
Vue.component('async-webpack-example', function (resolve) {
// do some thing
// 这个特殊的 `require` 语法将会告诉 webpack
// 自动将你的构建代码切割成多个包,这些包
// 会通过 Ajax 请求加载
require(['./my-async-component'], resolve)
})
import
会返回一个Promise
对象- 可自定义异步加载状态【根据加载处理的状态来改变要渲染的组件】
- loading
- error
- delay
- timeout
async-webpack-example.vue【在组件引用这个组件】
情况1:全局注册组件,并异步加载
Vue.component('async-webpack-example',
() => import('./my-async-component')
)
//-----------或者--------------------
Vue.component('async-webpack-example',
() => ({
component: import('./MyComponent.vue'),
// 加载时使用的组件
loading: LoadingComponent,
// 加载失败时使用的组件
error: ErrorComponent,
// 展示加载时组件的延时时间。默认值是 200 (毫秒)
delay: 200,
// 如果提供了超时时间且组件加载也超时了,
// 则使用加载失败时使用的组件。默认值是:`Infinity`
timeout: 3000
})
)
情况2:局部注册组件,并异步加载【根实例】
new Vue({
components: {
'async-webpack-example': () => import('./my-async-component')
}
})
处理边界情况
处理边界情况之$root
,$parents
,$refs
【可替代将数据以 prop 的方式传入子组件】
$root
,$parents
都能实现访问父组件的属性和方法$root
访问到的是它的根组件$parents
访问到的是最近一级的父组件
$refs
只会在组件渲染完成之后生效,并且它们不是响应式的。- 避免在模板或计算属性中访问 $refs
子组件访问根实例【$root】
new Vue
根实例,其子组件可以通过$root
属性进行访问
new Vue({
data: {
foo: 1
},
computed: {
a: function () { /* ... */ }
},
methods: {
b: function () { /* ... */ }
}
})
// 获取根组件的数据
this.$root.foo
// 写入根组件的数据
this.$root.foo = 2
// 访问根组件的计算属性
this.$root.a
// 调用根组件的方法
this.$root.b()
子组件访问最近一级的父组件【$parents】
- 最近一级的父组件,其子组件可以通过
$parents
属性进行访问
<div id="app">
<root-obj></root-obj>
</div>
//子组件(是子子组件的父组件)
Vue.component('root-obj', {
data() {
return {
}
},
template: `<div>
<button @click='getRoot'>子组件</button>
<child-component></child-component>
</div>`,
methods: {
getRoot() {
//得到自己
console.log(this)]
//得到var app = new Vue({})【根组件即这个的父组件】
console.log(this.$parent)
//得到var app = new Vue({})
console.log(this.$root)
}
}
})
//子子组件
Vue.component('child-component', {
data() {
return {
}
},
template: `<div>
<button @click='getRoot'>子子组件</button>
</div>`,
methods: {
getRoot() {
//得到自己
console.log(this)]
//得到Vue.component('root-obj', {})
console.log(this.$parent)
//得到var app = new Vue({})
console.log(this.$root)
}
}
})
//根组件
var app = new Vue({
el: '#app',
data: {
msg: 'Root'
}
})
父组件访问子组件实例【 ref
和 $refs
最常用】
- 最近一级的父组件,其子组件可以通过
$parents
属性进行访问- 避免在模板或计算属性中访问 $refs
- 只会在组件渲染完成之后生效
实例1:vue-cli的单组件形式
首先子组件需添加ref="属性值"
,然后即可使用使用$refs.ref的属性值
父组件
<template>
<base-alert ref="baseAlert"></base-alert>
<div @click="clickMe">click me</div>
</template>
<script>
import BaseAlert from '@/components/BaseAlert'
export default {
components: {
BaseAlert
},
methods: {
clickMe () {
//popUp 方法在子组件中定义
this.$refs.baseAlert.popUp()
}
}
}
</script>
<style scoped>
div {
width: 20px;
height: 20px;
background: red;
margin-top: 100px
}
</style>
子组件
<template>
<div>
<div>child component</div>
</div>
</template>
<script>
export default {
data () {
return {
}
},
methods: {
popUp () {
alert(abc)
}
}
}
</script>
实例2:
<div id="app">
<button @click='refView'>通过ref访问子组件</button>
</div>
//子组件
Vue.component('base-input', {
data() {
return {
msg: 'base-input'
}
},
template: `<input type='text'/>`
})
//根实例
var app = new Vue({
el: '#app',
data: {
msg: 'Root'
},
methods: {
refView() {
console.log(this.$refs.baseInput)
this.$refs.baseInput.$el.focus()
}
}
})
依赖注入 provide选项 和 inject选项
- 把依赖注入看作一部分“大范围有效的 prop”
- 明天再写,这里不太会