VueJS组件自定义(上)
前言¶
注: 这是阅读《循序渐进Vue.js 3前端开发实战》和官方文档等做的笔记
在Vue框架中,将网页甚至整个网站抽象为一个应用程序,即Web App,而这个Web App主要由各种组件组成;网站渲染的起点元素被称为 根组件 。
Vue App实例:根组件¶
创建一个Vue App实例:
注意到提供的参数为空,这便是一个默认的参数,可以通过传入参数提供一些配置选项。
data()选项¶
data()
选项是需要配置为一个JS函数,返回的是这个App所需要的全局数据:
props选项¶
props
选项是用于接收父组件传递的数据:
这里的根组件App一般不需要接收父组件传递的属性值。
computed选项¶
computed
选项是组件的计算属性,可以专门定义getter或setter函数来对读取、赋值进行分别操作:
const App = Vue.createApp({
computed:{
name:{
get(){
return this.name;
},
set(newName){
this.name = newName
}
},
age:{
get(){
return this.age;
}
}
}
})
methods选项¶
methods
选项是用来定义组件中使用的函数的地方:
watch选项¶
watch
选项是用来监听属性变化的,从而立即做出相应操作:
const App = Vue.createApp({
watch:{
name(value, newValue){
console.log(`name change from ${value} to ${newValue}`);
}
}
})
自定义组件:选项与方法¶
Vue App实例也是一个组件,只不过它是根组件,因此要定义一个组件,也是只需要包含相应的选项与方法即可:
const AlertComponent = {
data(){
return {
msg: "Alert Message",
count: 0
}
},
methods:{
click(){
alert(this.msg + this.count++)
}
},
template: `<div><button @click="click">Button</button></div>`
}
它走路像一只鸭子,看起来也像一只鸭子,那么它就是一只鸭子;好了,这就是定义了一个组件,其中template
选项定义的是组件的HTML模板。
对于选项和方法的设置,使得不同的组件具备不同的功能与特性。
挂载组件:映射为标签¶
将这个组件挂载到根组件,也就是Vue App实例上:
通过component
方法将组件的名字会映射到具体的组件定义,可以作为标签直接使用:
因为该组件只在App实例中挂载了,因此它只能在对应挂载标签内部使用,比如这里是id为Application的div标签,在外部是找不到这个组件定义的。
外部属性:灵活设置¶
所谓外部属性,即可以通过外部传递进来的属性,也就是前面提到的父组件通过props
属性传递数据进来:
const AlertComponent = {
props: ["title"],
data(){
return {
msg: "Alert Message",
count: 0
}
},
methods:{
click(){
alert(this.msg + this.count++)
}
},
template: `<div><button @click="click">Button: {{ title }}</button></div>`
}
这个props
定义的外部属性,这里是一个列表形式,但其还有另外的形式,比如检查类型、设置默认值、数据校验等。
外部属性列表的元素可以是任意多个,然后可以在模板部分直接访问到,对这个组件作为标签使用的时候,可以通过父组件传递不同的外部属性值:
Vue是单向数据流,即数据只可以从父组件流向子组件,如果子组件要将数据传回父组件,只能通过其它方式,比如响应事件。
组件产生事件:响应父组件¶
如果想要父组件知道子组件内部的反馈并进一步采取对应的操作,则需要子组件产生事件供父组件捕获,它是通过$emit
来产生事件的:
const AlertComponent = {
props: ["title"],
methods:{
click(){
this.$emit('myclick', this.title);
}
},
template: `
<div>
<button @click="$emit('myclick')">Button A: {{ title }}</button>
<button @click="$emit('myclick', 100)">Button B: {{ title }}</button>
<button @click="click">Button C: {{ title }}</button>
</div>
`
}
这个组件中通过三个方式产生事件,一个是默认参数或无参数,另一个是提供实参100,还有一个在函数中产生事件。
父组件使用这个组件标签的时候,如果想捕获这个事件并进行相应的操作,那么可以这样:
当然这里myfunc必须在父组件中已经定义的方法,它会在子组件产生myclick事件时自动捕获并被调用:
const App = Vue.createApp({
methods:{
myfunc(param){
console.log("$emit myclick has let the myfunc to be called with param:", param);
}
}
});
提供响应事件信号的方式,让父组件这个调用者可以根据子组件的反馈进行相应的操作,这是非常必要的。
组件支持v-model指令:双向绑定¶
通过v-bind
指令也可以实现v-model
指令的功能,就是通过先取值再赋值的形式,但v-model
将两步化为一步,实现双向绑定效果。
如果要让一个自定义组件也支持v-model
指令,则可以这样:
const InputComponent = {
props: ["modelValue"],
methods:{
action(event){
this.$emit('update:modelValue', event.target.value);
}
},
template: `
<div>
<input @input="action" :value="modelValue"/>
</div>
`
}
其原理就是v-model
指令默认会传递一个modelValue
外部属性到子组件,并捕获子组件产生的update:modelValue
事件,在父组件中将作为实参的新值替换旧值,使用方法:
组件的插槽(slot):定制化布局¶
比如,一个容器类组件,它需要包裹一些内部元素:
默认在组件渲染的时候是会丢掉的,但组件内部的元素其实是已经被捕获到一个插槽中的,只要在组件内部显式的调用这个插槽就可以让组件内部元素显示:
这样通过slot就将实例化组件时提供的内部元素可以显示了;如果没有提供内部元素,则插槽会使用默认内容,这非常实用。
还可以提供多个插槽,以在组件内部提供更高的定制性,需要使用插槽名字区分,比如容器类组件内部进行定制化布局:
const ContainerComponent = {
template: `
<div>
<slot name="slot1">默认内容1</slot>
<slot name="slot2">默认内容2: This is Part II.</slot>
<slot name="slot3">默认内容3</slot>
</div>
`
}
那么使用的时候,指定对应插槽名字即可:
<my-container>
<template v-slot:slot1>
<h1>This is Part I.</h1>
</template>
<template #slot3>
<h1>This is Part III.</h1>
</template>
</my-container>
其中,v-slot:
可以用缩写#
来代替。
动态组件:component标签¶
动态组件是Vue的一个高级功能,当需要根据情况将某个位置渲染为不同组件时,则需要用到它:
component
标签很特殊,它通过is属性
提供的组件名字,从而在该位置渲染为对应组件,因此只需要通过改变is属性
值就可以控制组件的切换。
属性命名规则¶
在定义组件的时候,对于外部属性和响应事件等的命名规则是小写字母驼峰式
,即小写字母开头,后面每个单词首字母大写,比如:
const myComponent = {
props:["myCatWeight", "color"],
methods:{
click(){
this.$emit("changeMyCatName", "Kitty");
}
}
}
但当这个组件作为标签用于HTML中时,传递这些外部属性和响应事件的写法变成了用-
符号连接的驼峰命名法
,比如:
<div id="Application">
<my-component @change-my-cat-name="func1" my-cat-weight="3.14" color="black"></my-component>
</div>
其实,Vue在构建的时候编译器会将组件内部的属性命名根据规则进行转换,转换后就和HTML中的写法对应上了。
全局组件¶
Vue App实例,也就是根组件,通过component
方法定义或映射的组件被称为全局组件
,虽然初期使用起来会比较方便,但随着组件数量增加会变得难以维护,而且有诸多限制,比如全局组件内部的模板属性值是通过字符串形式定义的,也无法在组件内部使用自己的CSS样式等。
与之对应的,是将组件定义为单文件组件
,即每个组件单独一个文件,在文件中包含了该组件的模板、脚本、CSS样式等,便于开发大型项目。
- 微信搜索: 「 MinYiLife 」, 关注公众号!
- 本文链接: https://www.lesliezhu.com/blog/2024/01/23/vuejs_4/
- 版权声明: 原创文章,如需转载请注明文章作者和出处。谢谢!