🌈个人主页:前端青山
🔥系列专栏:Vue篇
🔖人终将被年少不可得之物困其一生
依旧青山,本期给大家带来vue篇专栏内容-组件注册及使用
目录
1、组件的注册及使用
2、组件常用属性
2.1、directive
2.2、computed
2.3、watch
2.4、filter
2.5、mixin
1、组件的注册及使用
Vue的组件按照类型可以分为:
-
全局组件:只要注册好,可以在项目中任意.vue文件中使用
-
局部组件:主要注册好,可以在当前的.vue文件中使用
无论是全局组件还是局部组件,在使用时必须先对组件进行注册
全局组件通常在入口文件main.js
中注册,注册语法:
Vue.component("组件名",组件对象)
局部组件根据需要,在需要使用外部组件的那个组件自身中注册,注册分为两部,先导入目标组件,然后再注册,示例如下:
import CompName from "path of Component"
export default {
components: {
// 标签名: CompName,
}
}
当一个组件被注册好后,该组件就可以在对应的范围内被使用,使用时,将组件名以HTML标签语法进行使用即可:
<!-- 例如,某组件名为TabBar,则使用语法如下 -->
<template>
<TabBar></TabBar>
</template>
由于组件在使用的时候按照标签语法进行使用,因此强烈建议在注册组件时强烈采用大驼峰命名法,以此来避免和html标签重复,例如有组件名Form
的组件,在Vue及React中都是允许的,但是form
这样的组件名慎用!
2、组件常用属性
2.1、directive
directive,该属性用于自定义指令
除了核心功能默认内置的指令,Vue也允许开发者注册自定义指令。
自定义指令可以分为两种情况:
-
全局自定义指令【更加实用】
-
局部自定义指令
当在某个组件内,自身的局部自定义指令与全局自定义指令冲突时,以组件自身的局部自定义指令为准。
指令是帮助我们快速完成某些处理的语法糖,其本质也就是一些拥有固定函数名称的函数集合,这些函数会在特定的时间触发并自动执行,我们称之为钩子函数。指令支持以下钩子函数:
bind,当指令首次与标签元素绑定的时候触发
inserted,当标签元素被插入完成后触发(与bind的区别在于是否可以获取父节点)
update,当标签元素更新时触发
componentUpdated,当组件更新完毕后触发
unbind,当指令与标签解绑时触发
在自定义指令时,我们必须要根据业务需要从上面几个钩子函数中选取一个或几个合适的钩子函数,并准备好逻辑代码组成一个JavaScript对象。钩子函数支持俩个形参:
-
el:指令宿主对应的DOM对象
-
binding:指令绑定对象,可以通过该对象获取指令的名称、指令表达式等信息
全局自定义指令的注册,通常也是在入口文件main.js中完成,但指令的处理程序在编写的时候允许模块化,也建议采用模块化来保持入口文件中的代码可读性。
Vue.directive("不带v-的指令名",包含指令处理程序的对象)
局部自定义指令通常注册在对应的组件自身,处理程序自身往往也不需要模块化,可以直接写在组件内,当然如果这个指令也需要在其它组件中使用也是可以模块化的:
export default {
directives: {
// 不带v-的指令名: 包含指令处理程序的对象,
}
}
请注意,在自定义指令的方法中,不能像以前的methods
中的方法一样使用关键词this
,此时this
关键词指向undefined
。
案例:使用自定义指令实现以下效果
-
使用全局指令定义自定义的
v-color(传参)
,在元素被插入时设置内容颜色
例如:<div v-color="'red'">文字</div>
此时指令语法如下:
// 指令实则是一堆钩子函数的集合
// 使用全局指令定义自定义的`v-color(传参)`,在元素被插入时设置内容颜色
const obj = {
bind (el) {
// 获取不到父节点
console.log(el.parentNode)
},
inserted (el, binding) {
console.log(el, binding)
// 获取父节点
console.log(el.parentNode)
el.style.color = binding.value
}
}
export default obj
需要在入口文件main.js中导入并注册指令:
import color from './directives/color'
// 全局指令注册语法:Vue.directive(指令名,指令对象)
Vue.directive('color', color)
在App.vue文件中测试全局指令的使用:
<template>
<div>
<!-- 全局指令测试 -->
<div v-color="color">青山哥哥好帅啊</div>
<div v-color="'green'">青山哥哥好帅啊</div>
<div v-color="'blue'">青山哥哥好帅啊</div>
<div v-color="'pink'">青山哥哥好帅啊</div>
<div v-color="'orange'">青山哥哥好帅啊</div>
<div v-color="'grey'">青山哥哥好帅啊</div>
</div>
</template>
<script>
export default {
data () {
return {
color: 'red'
}
},
}
</script>
<style></style>
-
使用局部自定义指令实现
v-mobile(不传参)
验证用户输入的是否是合法的手机号,不合法时将输入框背景色设置成pink,边框设置成red;合法时,边框黑色,背景色白色。
2.2、computed
computed,该属性用于定义计算属性
模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。例如:
<div id="example">
{{ message.split('').reverse().join('') }}
{{ message.split('').reverse().join('') }}
{{ message.split('').reverse().join('') }}
</div>
在这个地方,模板不再是简单的声明式逻辑。你必须看一段时间才能意识到,这里是想要显示变量 message
的翻转字符串。当你想要在模板中的多处包含此翻转字符串时,就会更加难以处理。
所以,对于任何复杂逻辑,你都应当使用计算属性。
如果我们使用一个计算属性,假定计算属性名字叫resverseMessage,那么我们可以将翻转message的工作交给该属性去完成,那么我们视图部分就可以这么写了:
<div id="example">
<!-- 虽然模版简单了,但是针对数据的处理依然需要在计算属性声明的位置去书写,因此代码实际上没有减少。那么问题来了?我们为什么还推广建议使用计算属性呢? -->
{{ reserseMessage }}
</div>
计算属性没有全局和局部之分,按照以下语法声明计算属性:
export default {
computed: {
// 计算属性名 : Function,
}
}
计算属性默认只有 getter,不过在需要时你也可以提供一个setter:
export default {
computed: {
// 计算属性名 : { get: Function, set: Function },
}
}
-
get:对应的函数在调用该计算属性时被执行
-
set:对应的函数在给该计算属性赋值时被执行,形参为赋的值
计算属性的结果会被缓存,除非依赖的响应式数据变化才会重新计算。注意,如果某个依赖 (比如非响应式 property) 在该实例范畴之外,则计算属性是不会被更新的。
2.3、watch
watch,该属性用于定义监听器/侦听器
使用watch来侦听data中数据的变化,watch中的属性(watch是对象格式)一定是data 中已经存在的数据。(特殊情况除外)
使用场景:数据变化时执行异步或开销比较大的操作。
典型应用:在线汉字转拼音
监听器的语法如下:
export default {
watch: {
data中数据属性名: 函数名 | 函数 | 对象 | 回调函数数组,
}
}
特别需要注意,如果监听的数据是一个对象,则需要使用深度监听语法:
export default {
watch: {
data中对象属性名: {
deep: true,
handler(val,oldVal){
}
}
}
}
注意,不应该使用箭头函数来定义 watcher 函数。
案例:给定三个输入框,第一个为姓输入框,第二个为名输入框,第三个为姓名组合结果框;要求当用户更新姓或名后,第三个输入框自动生成完整的姓名结果。
== 面试题:computed与watch有什么区别?? ==
-
设计方式上的区别
-
计算属性:依赖数据的,只要数据不变,它会套用固定的流程去执行。我们写好之后一劳永逸的。
-
监听器:需要我们自己去写比较复杂的数据处理过程,比如说一些异步的操作、开销大的操作。
-
-
响应方式上的区别
-
计算属性:支持深度深度数据是否变化的监听的
-
监听器:默认不支持深度响应,仅支持字面量处理,但是其支持通过代码的改动来支持深度监听
-
2.4、filter
filter,该属性用于定义过滤器
注意:filter仅在Vue2.x中支持,Vue3.x中已废弃,针对后者建议通过computed或methods来替代实现
前端呈现的页面中,不泛很多数据是来自于后端接口请求得到的响应,而有些时候响应给我们的数据格式未必符合我们的要求。例如,如果你做一个功能需要显示一个字符串名单,但是后端给你的名单格式是一个数组,那么此时v-for
循环操作不太好操作,而我们需要实现数组
→字符串
的格式转化,这个时候就可以使用过滤器来解决这个问题。
过滤器没有全局和局部之分,哪个组件需要使用则在对应的组件中声明即可,例如:
export default {
filters: {
过滤器名: Function,
}
}
需要注意的是,过滤器对应的函数:
-
至少有1个形参,形参为待处理的数据(任意格式)
-
使用过滤器时,如果实参有n个,那么形参应该有n+1个;其中第一形参必定是待处理的数据,而后的形参与实参一一对应(例如:第二个形参对应着第一个实参,第三个形参对应着第二个实参....)
-
必须有返回值
定义好过滤器后,过滤器就可以与插值表达式一起在视图结构中使用了:
{{表达式 | 过滤器名}}
过滤器可以传递实参:
{{表达式 | 过滤器名(实参1,实参2,...)}}
当然过滤器也可以被连续调用:
{{表达式 | 过滤器名1 | 过滤器名2 | ...}}
理论上来说,只要一个过滤器的表达式有输出,后面就可以继续调用,无长度限制。
案例:给定以下数组,请使用过滤器将其处理成目标显示效果,为了考虑兼容,如果插值没有数据,请返回固定语句进行提示
const actors = [
{id: 11, name: "张三"},
{id: 22, name: "李四"},
{id: 33, name: "王麻子"},
{id: 44, name: "青山哥哥"}
]
如果有数据则显示如下:
本剧主演:张三 李四 王麻子 青山哥哥
如果没有数据则显示如下:
本剧主演:暂无
2.5、mixin
mixin,该属性用于定义混入
mixin是Vue中非常实用的一个功能,它能够实现一些代码片段的复用,它可以将一个混入对象(js普通对象)中的Vue选项混入到被混入的Vue组件中去。混入操作按照类型可以分为:
-
全局混入,全局混入也可以称之为叫强制混入
-
局部混入,局部混入也可以称之为叫按需混入
全局混入会将混入对象的选项混入到所有的Vue组件中去,除非项目中每个组件都需要这些Vue选项,否则该操作方式慎用,因为其可能导致其它组件运行不正常。
定义混入对象,混入对象与常规的Vue选项对象的声明基本一致,假设混入对象名称为obj,则:
// 将要复用的选项放到混入对象中去
const obj = {
methods: {}
data(){
return {}
},
filters: {
},
computed: {
},
// ....
}
它不一定需要所有的Vue选项,需要什么根据复用的需求而定,需要复用什么选项写入进去即可。但是由于工程化下整个项目共用一个Vue的el
选项,因此混入对象中一般不会有el
选项。
全局混入语法:
Vue.mixin(混入对象)
局部混入语法:
export default {
mixins: [混入对象1,混入对象2,....]
}
在一个混入对象被混入到一个组件的时候,混入对象中的选项可能与组件自身的选项存在冲突的情况,例如混入对象中的data中有一个msg属性,而组件自身的data中也有msg属性,在这种情况下,混入操作会按照固定的合并策略进行冲突合并:
-
如果冲突发生在data中,则以组件自身的data数据为准
-
如果是对象属性发生冲突(如methods、computed、filters等)则会合并成一个对象属性,如对象属性中的属性存在同名则以组件自身的为准
-
如果是钩子函数出现同名冲突,则混入对象中的钩子函数会与本组件自身的钩子函数合并成数组,所有钩子函数均会被执行,但同周期的钩子函数在执行的时候混入对象中的钩子函数会优先于本组件的钩子函数执行