大家好,我是前端嵐楓,一枚二線城市的程序媛,上篇主要跟分享了《VUE系列-Vue核心應用(二)》,今天主要跟大家分享我整理的vue的組件相關的,主要包括組件聲明、組件種類、組件間的幾種數據通信方式及一些常用的面試題,vue面試題相關的答案我後期會專門整理分享。
Vue中的組件是開發中非常重要的一部分,組件化的好處:方便維護、方便複用 、 減少不必要的渲染
一.組件的聲明
1.1 全局組件
<my-button></my-button>
Vue.component('my-button',{
template:'<button>點我啊</button>'
})
let vm = new Vue({
el:'#app'
})
1.2 局部組件
<my-button></my-button>
let vm = new Vue({
el:'#app',
components:{
'MyButton':{
template:'<button>按鈕</button>'
}
}
});
HTML不支持自閉合的自定義元素,在DOM模板裏永遠不要使用自閉合組件,在HTML中也不支持MyButton的寫法,所以組件調用全部使用短橫線連接的方式!
二.組件的數據
在組件中的數據必須是函數的形式,目的爲了保證每個組件間的數據數據相互獨立
'MyButton':{
data(){
return {content:'按鈕'}
},
template:'<button>{{content}}</button>'
}
三.組件的屬性應用及校驗
- 屬性應用
<my-button button-content="按鈕"></my-button>
components:{
'MyButton':{
props:['buttonContent'],
template:'<button>{{buttonContent}}</button>'
}
}
屬性在組件標籤上需要使用短橫線命名法,在組件中聲明需要採用駝峯命名法
- 屬性校驗
<my-button button-content="按鈕" :number="'1'"></my-button>
components:{
'MyButton':{
props:{
buttonContent:String,
arr:{
type:Array,
default:()=>([])
},
number:{
type:Number,
validator:(value)=>{
return typeof value == 'number'
}
},
},
template:'<button>{{buttonContent}} {{arr}} {{number}}</button>'
}
}
四.Vue組件間的通信
快速原型開發: 可以快速識別.vue文件封裝組件插件等功能,也是基於Vue-Cli
sudo npm install @vue/cli -g
sudo npm install -g @vue/cli-service-global
vue serve App.vue
4.1 Props傳遞數據
components
├── Grandson1.vue // 孫子1
├── Grandson2.vue // 孫子2
├── Parent.vue // 父親
├── Son1.vue // 兒子1
└── Son2.vue // 兒子2
在父組件中使用兒子組件
<template>
<div>
父組件:{{mny}}
<Son1 :mny="mny"></Son1>
</div>
</template>
<script>
import Son1 from "./Son1";
export default {
components: {
Son1
},
data() {
return { mny: 100 };
}
};
</script>
子組件接受父組件的屬性
<template>
<div>子組件1: {{mny}}</div>
</template>
<script>
export default {
props: {
mny: {
type: Number
}
}
};
</script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<!-- 將父組件的數據 通過兒子的屬性傳入 -->
{a:1,b:2,c:3}
<my a=1 b=2 c=3></my>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
// 單向數據流 父組件將數據傳遞給兒子
// 每個組件都應該有三部分 1) html 2) js 3) 樣式
let component = {
template:`<div>兒子 {{mny}} <button @click="change">更改</button></div>`,
// props:['mny'], // this.mny = 100
props:{ // 表示 我要對屬性進行校驗
mny:{
// 普通類型直接寫 默認值即可 如果是對象或者是數組 必須寫成函數返回值的效果
type:Object, // 類型校驗
default:()=>({a:1})// 默認值校驗
// required:true //必填校驗
}
},
methods:{
change(){
this.mny = 200; // 不靠譜,不應該兒子去更改父親數據
}
},
data(){
return {m:1}
},
beforeCreate(){ // 這裏可以描述 父子關係
console.log(this.$parent.$children[0] === this);
},
}
// Vue.component('my',component)
let vm = new Vue({
el:'#app',
beforeCreate(){
console.log(this.$children);
debugger;
},
data:{
arr:[1,2,3],
mny:'100'
},
components:{ // 在實例上註冊組件
my:component
}
});
// 組件的使用 三部 1)導入一個組件 2) 註冊 3) 使用 在當前組件定義的模板中使用
</script>
</body>
</html>
4.2 $emit使用
子組件觸發父組件方法,通過回調的方式將修改的內容傳遞給父組件
<template>
<div>
父組件:{{mny}}
<Son1 :mny="mny" @input="change"></Son1>
</div>
</template>
<script>
import Son1 from "./Son1";
export default {
methods: {
change(mny) {
this.mny = mny;
}
},
components: {
Son1
},
data() {
return { mny: 100 };
}
};
</script>
子組件觸發綁定自己身上的方法
<template>
<div>
子組件1: {{mny}}
<button @click="$emit('input',200)">更改</button>
</div>
</template>
<script>
export default {
props: {
mny: {
type: Number
}
}
};
</script>
這裏的主要目的就是同步父子組件的數據,->語法糖的寫法
.sync
<Son1 :mny.sync="mny"></Son1>
<!-- 觸發的事件名 update:(綁定.sync屬性的名字) -->
<button @click="$emit('update:mny',200)">更改</button>
v-model
<Son1 v-model="mny"></Son1>
<template>
<div>
子組件1: {{value}} // 觸發的事件只能是input
<button @click="$emit('input',200)">更改</button>
</div>
</template>
<script>
export default {
props: {
value: { // 接收到的屬性名只能叫value
type: Number
}
}
};
</script>
4.3 parent 、children
繼續將屬性傳遞
<Grandson1 :value="value"></Grandson1>
<template>
<div>
孫子:{{value}}
<!-- 調用父組件的input事件 -->
<button @click="$parent.$emit('input',200)">更改</button>
</div>
</template>
<script>
export default {
props: {
value: {
type: Number
}
}
};
</script>
如果層級很深那麼就會出現parent.parent.....我們可以封裝一個$dispatch方法向上進行派發
$dispatch
Vue.prototype.$dispatch = function $dispatch(eventName, data) {
let parent = this.$parent;
while (parent) {
parent.$emit(eventName, data);
parent = parent.$parent;
}
};
既然能向上派發那同樣可以向下進行派發
$broadcast
Vue.prototype.$broadcast = function $broadcast(eventName, data) {
const broadcast = function () {
this.$children.forEach((child) => {
child.$emit(eventName, data);
if (child.$children) {
$broadcast.call(child, eventName, data);
}
});
};
broadcast.call(this, eventName, data);
};
4.4 listeners
$attrs
批量向下傳入屬性
<Son2 name="小珠峯" age="10"></Son2>
<!-- 可以在son2組件中使用$attrs屬性,可以將屬性繼續向下傳遞 -->
<div>
兒子2: {{$attrs.name}}
<Grandson2 v-bind="$attrs"></Grandson2>
</div>
<template>
<div>孫子:{{$attrs}}</div>
</template>
$listeners
批量向下傳入方法
<Son2 name="小珠峯" age="10" @click="()=>{this.mny = 500}"></Son2>
<!-- 可以在son2組件中使用listeners屬性,可以將方法繼續向下傳遞 -->
<Grandson2 v-bind="$attrs" v-on="$listeners"></Grandson2>
<button @click="$listeners.click()">更改</button>
4.5 Provide & Inject
Provide
在父級中注入數據
provide() {
return { parentMsg: "父親" };
},
Inject
在任意子組件中可以注入父級數據
inject: ["parentMsg"] // 會將數據掛載在當前實例上
provide inject 和 context (可以在父組件中聲明一個公共數據),在子組件中可以注入原理 (比較混亂,名稱問題 他不會在業務代碼中使用) 組件庫 多級通信爲了方便你可以使用provide
4.6 Ref使用
獲取組件實例
ref 獲取真實dom元素,如果放到組件上 代表的是 當前組件的實例 ,父組件中可以直接獲取子組件的方法或者數據
<Grandson2 v-bind="$attrs" v-on="$listeners" ref="grand2"></Grandson2>
mounted() { // 獲取組件定義的屬性
console.log(this.$refs.grand2.name);
}
4.7 EventBus
用於跨組件通知(不復雜的項目可以使用這種方式)
Vue.prototype.$bus = new Vue();
eventbus (children) 綁定on的那個組件來觸發 (混亂)
Son2組件和Grandson1相互通信
mounted() {
this.$bus.$on("my", data => {
console.log(data);
});
},
mounted() {
this.$nextTick(() => {
this.$bus.$emit("my", "我是Grandson1");
});
},
五.面試題環節
- 組件間通信方式