Vue两大核心: 1.数据驱动界面改变 2.组件化
自定义全局组件
-
1.什么是组件? 什么是组件化?
- 1.1在前端开发中组件就是把一个很大的界面拆分为多个小的界面, 每一个小的界面就是一个组件
- 1.2将大界面拆分成小界面就是组件化
-
2.组件化的好处
- 2.1可以简化Vue实例的代码
- 2.2可以提高复用性
-
3.Vue中如何创建组件?
- 3.1创建组件构造器
- 3.2注册已经创建好的组件
- Vue.component(参数1, 参数2);
- 第一个参数:指定注册的组件的名称
- 第二个参数:传入已经创建好的组件构造器
- Vue.component(参数1, 参数2);
- 3.3使用注册好的组件
- 示例:
- 注意点:
- ==在创建组件指定组件的模板的时候,模板只能有一个根元素==
创建组件的其它方式
- 1.在注册组件的时候,除了传入一个组件构造器以外, 还可以直接传入一个对象(参数2的位置会自动执行Vue.extend())
- 第一种,对象单独定义,Vue.component(组件名称,对象名称)
- 第二种,把对象直接放入参数2的位置
- 示例:
// 第一种
// 第二种
Vue.component('abc', {template: `
我是描述信息
`});
- 2.在编写组件模板的时候,除了可以在字符串模板中编写以外, 还可以像过去的art-template一样在script中编写(不建议)
- 示例:
- 3.在编写组件模板的时候,除了可以在script中编写以外, vue还专门提供了一个自定义组件模板的标签template(简化,方便,==推荐==)
- 示例:
我是描述信息
自定义局部组件
-
1.自定义全局组件特点
- 在任何一个Vue实例控制的区域中都可以使用
-
2.自定义局部组件特点
- 只能在自定义的那个Vue实例控制的区域中可以使用
-
3.如何自定义一个局部组件
- 1.在vue实例中新增components: {}
- 2.在{}中通过key/vue形式注册组件
components:{ abc: {} }
- 示例:
我是描述信息
自定义组件中的data和methods
-
1.自定义组件中的data和methods
- Vue实例控制的区域相当于一个大的组件,在大组件中我们可以使用data和methods
- 而我们自定义的组件也是一个组件,所以在自定义的组件中也能使用data和methods
-
2.自定义组件中data注意点
- methods使用方法一样
- data不一样,自定义组件中的data要求必须是一个函数
- 所以必须通过返回函数的方式来使用data
- 示例:
{{abcMsg}}
- 3.组件中的data为什么是一个函数?
- 因为自定义组件可以复用,为了保证复用时每个组件的数据都是独立的, 所以必须是一个函数
- 组件中的data如果不是通过函数返回的,那么多个组件就会公用一份数据,就会导致数据混乱;如果组件中的data是通过函数返回的,那么每创建一个新的组件,都会调用一次这个方法,将这个方法返回的数据和当前创建的组件绑定在一起,这样就有效的避免了数据混乱
- 因为自定义组件可以复用,为了保证复用时每个组件的数据都是独立的, 所以必须是一个函数
{{number}}
组件切换
- 组件切换
- 对于普通的元素我们可以通过v-if来实现切换,对于组件我们也可以通过v-if来实现切换,因为组件的本质就是一个自定义元素
我是首页
动态组件
-
1.什么是动态组件?
- 通过v-if/v-else-if/v-else确实能够切换组件,但是在Vue中切换组件还有一种更专业的方式
- component我们称之为动态组件,也就是你让我显示谁我就显示谁
- 通过v-if/v-else-if/v-else确实能够切换组件,但是在Vue中切换组件还有一种更专业的方式
-
2.为什么可以通过v-if切换还要有component
- 因为component可以配合keep-alive来保存被隐藏组件隐藏之前的状态,不写keep-alive的话默认是不保存之前状态的
- 示例:
微双
组件动画
- 1.如何给组件添加动画?
- 给组件添加动画和过去给元素添加动画一样,如果是单个组件就使用transition,如果是多个组件就使用transition-group
- 示例:
微双
- 2.过渡动画注意点
- 默认情况下进入动画和离开动画是同时执行的,如果想一个做完之后再做另一个,需要指定动画模式
- 示例中在transition中添加
mode="out-in"
- 示例中在transition中添加
- 默认情况下进入动画和离开动画是同时执行的,如果想一个做完之后再做另一个,需要指定动画模式
父子组件
-
1.什么是父子组件?
- 在一个组件中又定义了其它组件就是父子组件
- 其实局部组件就是最简单的父子组件,因为我们说过可以把Vue实例看做是一个大组件。我们在Vue实例中定义了局部组件,就相当于在大组件里面定义了小组件,所以实局部组件就是最简单的父子组件
-
2.如何定义其它的父子组件
- 前面我们说过, 自定义组件中可以使用data, 可以使用methods.当然自定义组件中也可以使用components,所以我们也可以在自定义组件中再定义其它组件
- 示例:
我是父组件
我是子组件
父子组件数据传递
-
1.父子组件数据传递?
- 在Vue中子组件是不能访问父组件的数据的(就是子组件不继承父组件的数据),如果子组件想要访问父组件的数据,必须通过父组件传递
-
2.如何传递数据
- 2.1在父组件中通过v-bind传递数据
- 传递格式
v-bind:自定义接收名称 = "要传递数据"
- 传递格式
- 2.2在子组件中通过props接收数据
- 接收格式
props: ["自定义接收名称"]
- 接收格式
- 示例:
- 2.1在父组件中通过v-bind传递数据
{{name}}
{{age}}
{{def}}
{{abc}}
备注:上面示例的模板可以换成全局组件,根据需求
- ==注意点==
- 组件是可以使用自己的数据的
- 子组件要用传递过来自定义的名称,用父组件原名称是无效的
父子组件传递方法
- 和传递数据不同,如果传递的是方法,那么在子组件中不需要接收,需要进行如下操作:
- 1.需要在子组件中自定义一个方法
- 2.在子组件中直接使用自定义的方法
- 3.在子组件自定义的方法中通过
this.$emit("自定义接收的名称")
的方法来触发父组件传递过来的方法 - 示例:
子组件传递数据给父组件
- 如何将子组件数据传递给父组件
- 既然我们可以将父组件的方法传递给子组件,既然我们可以在子组件中调用父组件中的方法,那么我们就可以在调用方法的时候给方法传递参数
- 传递的参数, 就是我们需要传递的数据
- 格式
this.$emit(参数1, 参数2);
- 第一个参数: 需要调用的函数名称
- 第二个参数:给调用的函数传递的参数
- 示例:
组件中的命名注意点
- 1.组件中的命名注意点
- 1.1注册组件的时候使用了"驼峰命名", 那么在使用时需要转换成"短横线分隔命名"
- 例如: 注册时:
myFather
-> 使用时需改为:my-father
- 例如: 注册时:
- 1.2在传递参数的时候如果想使用"驼峰名称", 那么就必须写"短横线分隔命名"
- 例如: 传递时:
parent-name="name"
-> 接收时需改成:props: ["parentName"]
- 例如: 传递时:
- 1.3在传递方法的时候不能使用"驼峰命名", 只能用"短横线分隔命名"
@parent-say="say" -> this.$emit("parent-say");
- 1.1注册组件的时候使用了"驼峰命名", 那么在使用时需要转换成"短横线分隔命名"
==总结:命名别用驼峰命名法,正常小写命名就好,省事==
数据和方法的多级传递
- 数据和方法的多级传递
- 在Vue中如果儿子想使用爷爷的数据, 必须一层一层往下传递
- 在Vue中如果儿子想使用爷爷的方法, 必须一层一层往下传递
- 示例:
{{name}}
{{gfname}}
{{fname}}
插槽
- 什么是插槽?
- 默认情况下使用子组件时在子组件中编写的元素是不会被渲染的
- 如果子组件中有部分内容是使用时才确定的, 那么我们就可以使用插槽,也就是说想在使用子组件的时候,给子组件动态的添加内容, 那么就必须使用插槽
- 插槽就是在子组件中放一个"坑"
,以后由父组件来"填" - 示例:
我是追加的内容1
我是追加的内容2
我是追加的内容3
我是头部
我是默认数据
我是底部
- ==注意点==:
- 插槽可以指定默认数据,如果使用者没有填这个坑,那么就会显示默认数据。如果使用者填了这个坑,那么就会利用使用者填坑的内容替换整个插槽
- 插槽是可以指定名称的,默认情况下如果没有指定名称
- 有多少个匿名插槽,填充的数据就会被拷贝几份
匿名插槽
- 什么是匿名插槽
- 没有名字的插槽,会利用使用时指定的能容替换整个插槽(如上面的示例)
- ==注意点==:如果有多个匿名插槽,每一个匿名插槽都会被指定的内容替换。虽然写多个匿名插槽不会报错,但是==在企业开发中推荐只能有一个匿名插槽==
具名插槽
-
1.什么是具名插槽
- 默认情况下有多少个匿名插槽,我们填充的数据就会被拷贝多少份,这导致了所有插槽中填充的内容都是一样的,那么如果我们想给不同的插槽中填充不同的内容怎么办呢?
- 这个时候就可以使用具名插槽
-
2.具名插槽使用
- 通过插槽的name属性给插槽指定名称,在使用时可以通过
slot="name"
方式,指定当前内容用于替换哪一个插槽 - 示例:
- 通过插槽的name属性给插槽指定名称,在使用时可以通过
我是追加的内容1
我是追加的内容11
我是追加的内容2
我是追加的内容22
我是头部
我是默认内容
我是默认内容
我是底部
- 注意点:
- ==如果没有指定要替换哪个插槽中的内容, 则不会被替换==
v-slot指令
- 什么是v-slot指令?
- v-slot指令是Vue2.6中用于替代slot属性的一个指令
- 在Vue2.6之前,我们通过slot属性告诉Vue当前内容填充到哪一个具名插槽
- 从Vue2.6开始,我们通过v-slot指令告诉Vue当前内容填充到哪一个具名插槽
- 示例:
//只需把上节父组件在填充子组件的代码:
我是追加的内容1
我是追加的内容11
我是追加的内容2
我是追加的内容22
// 换成:
我是追加的内容1
我是追加的内容11
我是追加的内容2
我是追加的内容22
- ==注意点==:
- v-slot指令只能用在template标签上
- 格式
v-slot:插槽名称
- 可以使用#号替代v-slot:变成
#插槽名称
作用域插槽(不推荐使用)
-
1.什么是作用域插槽
- 作用域插槽就是带数据的插槽,就是让父组件在填充子组件插槽内容时也能使用子组件的数据
-
2.如何使用作用域插槽
- 2.1在slot中通过
v-bind:数据名称="数据名称"
方式暴露数据 - 2.2在父组件中通过
接收数据
- 2.3在父组件的
中通过
作用域名称.数据名称
方式使用数据 - 示例:
- 2.1在slot中通过
{{name}}
我是头部 {{names}}
我是默认内容 {{names}}
我是底部
- 作用域插槽的应用场景:
- 子组件提供数据, 父组件决定如何渲染
通过v-slot也可以接收作用域暴露的数据
- 也就是说我们除了可以通过v-slot指令告诉Vue内容要填充到哪一个具名插槽中,==还可以通过v-slot指令告诉Vue如何接收作用域插槽暴露的数据(推荐用v-slot,它取代了 slot 和 slot-scope)==
- 格式
- 第一种
v-slot:插槽名称="作用域名称"
- 第二种
v-slot:default='作用域名称'
- 第三种
#default='作用域名称'
- 第一种
- 示例(上个示例):
- 格式
// 三种写法,上个示例中父组件和子组件部分改为如下即可
{{name}}
我是头部 {{names}}
我是默认内容 {{names}}
我是底部
数据传递练习(理解,不是最优版,可以用Vue优化)
- 如何实现儿子中的数据和父亲中的数据同步
- 1.父亲给儿子传递一个方法
- 2.在儿子中修改数据
- 3.儿子中修改完数据,调用父亲传递过来的方法, 并且将修改之后的数据传递给父亲的方法
- 4.在父亲的方法中保存最新的数据
{{parentnum}}
-
以上写法不是最优版的原因:
- 两个问题:
- 1.如果想要在子组件中使用祖先组件中的数据,那么就必须一层一层的传递(非常麻烦)
- 2.兄弟组件之间不能直接传递数据,如果兄弟组件之间想要传递数据,那么就必须借助父组件(非常麻烦),这种方式非常的复杂, 非常的不推荐
- 两个问题:
解决方案: 使用Vuex
共享数据Vuex
- 1.什么是Vuex?
- vuex是Vue配套的公共数据管理工具,它可以把一些共享的数据,保存到vuex中,方便整个程序中的任何组件直接获取或修改我们的公共数据
- 示例:
{{this.$store.state.msg}}
{{this.$store.state.msg}}
{{this.$store.state.msg}}
- 注意点:
- ==必须在引入Vue之后再引入Vuex==
- ==只有需要共享的才放到vuex上,不需要共享的数据依然放到组件自身的data上==
数据传递练习(上面的优化版)
- 注意点:
- 在Vuex中不推荐直接修改共享数据
- 如果多个组件都修改了共享的数据,那么后期数据发生了错误,我们如果需要去调试错误,就需要把每一个修改了共享数据的组件都检查一遍,这样非常低效,非常的不利于我们去维护
- 解决方法:在Vuex中添加
mutations
- 示例:
Vuex-getters
- 什么是Vuex的getters?
- Vuex的getters属性就和组件的计算属性一样, 会将数据缓存起来,只有数据发生变化才会重新计算
- 示例:
{{this.$store.getters.formart}}
{{this.$store.getters.formart}}
{{this.$store.getters.formart}}