一. 元件入門
1. 命名方式
(1). 使用kebab-case(短橫線分割符)【推薦!】
當使用 kebab-case (短橫線分隔命名) 定義一個元件時,你也必須在引用這個自定義元素時使用 kebab-case,例如 <my-component-name>;

(2). 使用PascalCase(駝峰辨別符)
當使用 PascalCase (首字母大寫命名) 定義一個元件時,你在引用這個自定義元素時兩種命名法都可以使用。也就是說 <my-component-name> 和 <MyComponentName> 都是可接受的;
2. 父元件、子元件、兄弟元件等
如下圖:App元件中調用Header、Main、Footer元件,Main元件中調用Banner、ProductList元件,那麼:
(1). App元件是Header、Main、Footer元件的父元件;(Header、Main、Footer元件是App元件的子元件)
(2). Main元件是Banner、ProductList元件的父元件;(Banner、ProductList元件是Main元件的子元件)
3. 全局元件
全局元件往往是在應用程式一開始就會全局元件完成,那麼就意味着如果某些元件我們并沒有用到,也會一起被注冊:
代碼分享:
<body>
<div id="app"></div>
<template id="myApp">
<div>
{{msg}}
</div>
<!-- 使用元件 -->
<ypf-a></ypf-a>
<ypf-b></ypf-b>
</template>
<template id="myApp1">
<div>
{{msg1}}
</div>
</template>
<template id="myApp2">
<div>
{{msg2}}
</div>
</template>
<script src="../js/vue3.js"></script>
<script>
const app = Vue.createApp({
template: '#myApp',
data() {
return {
msg: 'Hello Vue3!'
}
}
});
// 注冊全局元件
app.component("ypf-a", {
template: "#myApp1",
data() {
return {
msg1: "元件1",
};
}
});
app.component("ypf-b", {
template: "#myApp2",
data() {
return {
msg2: "元件2",
};
},
});
app.mount('#app');
</script>
</body>
View Code
4. 局部元件
局部注冊是在我們需要使用到的元件中,通過components屬性選項來進行注冊;
代碼分享:
<body>
<div id="app"></div>
<template id="myApp">
<div>
{{msg}}
</div>
<!-- 使用元件 -->
<ypf-a></ypf-a>
<ypf-b></ypf-b>
</template>
<template id="myApp1">
<div>
{{msg1}}
</div>
</template>
<template id="myApp2">
<div>
{{msg2}}
</div>
</template>
<script src="../js/vue3.js"></script>
<script>
// 注冊局部元件
const ypf1 = {
template: "#myApp1",
data() {
return {
msg1: "元件1",
};
}
};
const ypf2 = {
template: "#myApp2",
data() {
return {
msg2: "元件2",
};
},
};
Vue.createApp({
template: '#myApp',
components: {
// key: 元件名稱
// value: 元件對象
'ypf-a': ypf1,
'ypf-b': ypf2
},
data() {
return {
msg: 'Hello Vue3!'
}
}
}).mount('#app');
</script>
</body>
5. 單檔案vue元件的使用
App元件
<template>
<div>
<Header></Header>
<Main></Main>
<Footer></Footer>
</div>
</template>
<script>
import Header from './Header.vue';
import Footer from './Footer.vue';
import Main from './Main.vue';
export default {
components: {
Header,
Footer,
Main
},
data() {
return {};
}
}
</script>
<style scoped>
</style>
Header元件
<template>
<div>
我是Header元件
</div>
</template>
<script>
export default {
components: {
},
data() {
return {};
}
}
</script>
<style scoped>
</style>
Main元件
<template>
<div>
<main-banner></main-banner>
<main-product-list></main-product-list>
</div>
</template>
<script>
import MainBanner from './MainBanner.vue';
import MainProductList from './MainProductList.vue';
export default {
components: {
MainBanner,
MainProductList
},
data() {
return {};
}
}
</script>
<style scoped>
</style>
Footer元件
<template>
<div>
我是Footer元件
</div>
</template>
<script>
export default {
components: {
},
data() {
return {};
}
}
</script>
<style scoped>
</style>
MainBanner元件
<template>
<div>
我是MainBanner元件
</div>
</template>
<script>
export default {
components: {
},
data() {
return {};
}
}
</script>
<style scoped>
</style>
MainProductList元件
<template>
<div>
<ul>
<li>産品1</li>
<li>産品2</li>
<li>産品3</li>
<li>産品4</li>
<li>産品5</li>
</ul>
</div>
</template>
<script>
export default {
components: {
},
data() {
return {};
}
}
</script>
<style scoped>
</style>
1. 補充元件聲明調用的幾種方式
(1). 元件檔案的命名可以 駝峰 和 短橫線。
(2). 導入并聲明
<script>
// 導入元件(此處的名稱不能寫 分隔符!!)
import GetMsg1 from './component/GetMsg1.vue';
import GetMsg2 from './component/get-msg2.vue';
export default {
components: {
// 下面寫法在調用的時候支援 駝峰 和 短橫線分隔符
GetMsg1,
GetMsg2,
// 強制寫成短橫線分隔符
'my-get-msg1': GetMsg1,
'my-get-msg2': GetMsg2,
},
}
</script>
(3). 調用
<template>
<div>
<!-- 可以直接使用駝峰 或者 使用短橫線分割符 -->
<get-msg1></get-msg1>
<GetMsg1></GetMsg1>
<!-- 可以直接使用駝峰 或者 使用短橫線分割符 -->
<get-msg2></get-msg2>
<GetMsg2></GetMsg2>
<!-- 直接使用短橫線分隔符-->
<my-get-msg1></my-get-msg1>
<my-get-msg2></my-get-msg2>
</div>
</template>
2. 補充UniApp中元件的調用規範
(1). 傳統用法(不推薦)
A. 局部元件
B. 全局元件
(2). 特有easycom用法
uni-app 2.7以後推出了更簡單的元件使用技術easycom,無需引用和注冊元件,直接在template區域使用元件即可。
傳統vue元件,需要安裝、引用、注冊,三個步驟後才能使用元件。
easycom
将其精簡為一步。 隻要元件安裝在項目的components目錄下,并符合
components/元件名稱/元件名稱.vue
目錄結構。就可以不用引用、注冊,直接在頁面中使用。
二. 父傳子
1. 說明
(1). 父元件向子元件傳值,主要通過props來完成元件之間的通信。 即在子元件的props中聲明一些屬性,父元件給這些屬性指派,子元件通過屬性的名稱擷取到對應的值。
(2). Props有兩種常見的用法:
方式一:字元串數組,數組中的字元串就是attribute的名稱;
方式二:對象類型,對象類型我們可以在指定attribute名稱的同時,指定它需要傳遞的類型、是否是必須的、預設值等等;
2. props為字元串數組
子元件代碼:
<template>
<div>
<h5>我是ChildMsg1元件</h5>
<h5 class="c1">title的為:{{title}}</h5>
<h5 class="c1">content的為:{{content}}</h5>
</div>
</template>
<script>
export default {
props: ['title', 'content'],
// 禁用根元素繼承非prop和emit的屬性
inheritAttrs: false,
data() {
return {};
}
}
</script>
父元件代碼
<template>
<div>
<!-- 調用ChildMsg1元件 -->
<child-msg1 title='西遊記' content='真假美猴王'></child-msg1>
<child-msg1 :title='myTitle' :content='myContent'></child-msg1>
</div>
</template>
<script>
export default {
data() {
return {
myTitle: '水浒傳',
myContent: '智取生辰綱',
};
}
}
</script>
運作效果:
3. props為對象
(1). 使用對象文法的時候,我們可以對傳入的内容限制,比如類型限制、必填限制、預設值等。
(2). type的類型都可以是哪些呢?String、Number、Boolean、Array、Object、Date、Function、Symbol。
(3). HTML 中的 attribute 名是大小寫不敏感的,是以浏覽器會把所有大寫字元解釋為小寫字元;
子元件:
<template>
<div>
<h5>我是ChildMsg2元件</h5>
<h5 class="c1">messageInfo的為:{{messageInfo}}</h5>
<h5 class="c1">messageInfo2的為:{{messageInfo2}}</h5>
<h5 class="c1">propA的為:{{propA}}</h5>
<h5 class="c1">propB的為:{{propB}}</h5>
<h5 class="c1">message的為:{{propC.message}}</h5>
</div>
</template>
<script>
export default {
props: {
// 基礎類型檢查
messageInfo: String,
// 多個可能的類型
messageInfo2: [String, Number],
// 必填字元串
propA: {
type: String,
required: true
},
// 含有預設值的字元串
propB: {
type: String,
default: '我是content的預設值哦'
},
// 含預設值的對象
propC: {
type: Object,
// 引用類型(對象、數組)預設值必須從一個工廠函數中擷取
//引用類型指向同一個位址,修改會互相覆寫
default () {
return { message: 'hello component' }
}
},
// 自定義驗證函數
propF:{
validator(value){
return ['success','warning','danger'].includes(value);
}
},
// 具有預設值的函數
propG:{
type:Function,
// 注:與對象或數組的預設值不同,這不是一個工廠函數,而是一個用作預設值的函數。
default(){
return 'Default function';
}
}
},
data() {
return {};
}
}
</script>
父元件:
<template>
<div>
<!-- 調用ChildMsg2元件 -->
<child-msg2 messageInfo="你好1" message-info2="你好2" :propA="myObj.propA" :propB="myObj.propB" :propC="myObj.propC"></child-msg2>
</div>
</template>
<script>
export default {
data() {
return {
myObj: {
propA: 'hello propA',
propB: 'hello propB',
propC: { message: 'hello propC' }
}
};
}
}
</script>
4. 非props的屬性說明
如何禁用呢?
在子元件中使用inheritAttrs屬性。
<script>
export default {
props: ['title', 'content'],
// 禁用根元素繼承非prop和emit的屬性
inheritAttrs: false,
data() {
return {};
}
}
</script>
三. 子傳父
(1). 背景
子元件有一些内容想要傳遞給父元件的時候,再比如,當子元件有一些事件發生的時候,在元件中發生了點選,父元件需要根據子元件傳遞的資訊切換内容;
(2). 實作思路
A. 我們需要在子元件中定義好在某些情況下觸發的事件名稱;先使用 emits屬性聲明對外暴露的方法 → 再使用$emit對聲明的方法對外傳遞。
PS:在Vue2.x中,可以不用emits事先聲明,但Vue3.x中需要,否則會報警告。
B. 在父元件中以v-on的方式(簡寫@)傳入要監聽的事件名稱,并且綁定到對應的方法中;
C. 在子元件中發生某個事件的時候,根據事件名稱觸發對應的事件;
2. 實戰
(1). 子元件
通過$emit方法,可以向外聲明暴露的方法,同時還可以傳遞1個或多個參數。
<template>
<div>
<button @click="increment">增加</button>
<button @click="decrement">減少</button>
<button @click="cdMany">測試傳遞多個參數</button>
</div>
</template>
<script>
export default {
// 寫法1
emits: ['addN', 'subN', 'cdN'],
methods: {
increment() {
this.$emit('addN', 2);
},
decrement() {
this.$emit('subN', 5);
},
// 傳遞多個參數
cdMany() {
this.$emit('cdN', 'ypf1', 20, '哈哈');
}
}
}
</script>
(2). 父元件
通過@符号,調用子元件$emits傳遞出來的方法,進而和自己聲明的方法進行綁定,同時接收參數。
<template>
<div>
<div>{{count}}</div>
<child-msg1 @addN='add' @subN='sub' @cdN='testCdN'></child-msg1>
</div>
</template>
<script>
import ChildMsg1 from './ChildMsg1.vue';
export default {
components: {
ChildMsg1
},
data() {
return {
count: 0,
};
},
methods: {
add(n) {
this.count += n;
},
sub(n) {
this.count -= n;
},
testCdN(name, age, msg) {
console.log(name, age, msg);
}
}
}
</script>
(3). 運作結果
3. 參數驗證
子元件中的emits可以聲明成對象,可以對其增加驗證。
<template>
<div>
<button @click="increment">增加</button>
<button @click="decrement">減少</button>
<button @click="cdMany">測試傳遞多個參數</button>
</div>
</template>
<script>
export default {
// 寫法2(自定義參數和驗證)
emits: {
addN: null,
subN: null,
// 不符合的話,會有警告提示
cdN: (name, age, msg) => {
if (age>10) {
return true;
} else{
return false;
}
}
},
data() {
return {};
},
methods: {
increment() {
this.$emit('addN', 2);
},
decrement() {
this.$emit('subN', 5);
},
// 傳遞多個參數
cdMany() {
this.$emit('cdN', 'ypf1', 20, '哈哈');
}
}
}
</script>
四. 爺傳孫
比如我們現在結構是 App→FatherMsg→ChildMsg1 的調用關系, App和ChildMsg1元件中并不是直接的父子關系,App元件想直接向ChildMsg1元件中傳值,這個使用就需要通過 Provide 和 Inject 來實作了。
通過嵌套層次有多深,都可以通過:
上級元件(App)有一個 provide 選項來提供資料;
下級元件(ChildMsg1)有一個 inject 選項來開始使用這些資料;
2. 實戰
(1). App元件代碼
<template>
<div>
<father-msg></father-msg>
<div><button type="button" @click="addItem">增加資料</button></div>
</div>
</template>
<script>
import FatherMsg from './FatherMsg.vue';
import { computed } from 'vue';
export default {
provide() {
return {
name: 'ypf',
age: 18,
// length: this.arry1.length
length: computed(() => this.arry1.length)
}
},
components: {
FatherMsg
},
data() {
return {
arry1: ['t1', 't2', 't3']
};
},
methods: {
addItem() {
this.arry1.push('t4');
}
}
}
</script>
(2). FatherMsg元件代碼
<template>
<div>
<child-msg1></child-msg1>
</div>
</template>
<script>
import ChildMsg1 from './ChildMsg1.vue';
export default {
components: {
ChildMsg1
},
data() {
return {};
}
}
</script>
(3). ChildMsg1元件代碼
<template>
<div>
<!-- {{name}}--{{age}}--{{length}} -->
<!-- 響應式顯示 -->
{{name}}--{{age}}--{{length.value}}
</div>
</template>
<script>
export default {
inject: ['name', 'age', 'length']
}
</script>
補充:處理響應式資料
給數組添加内容,想讓inject中的length跟着變化,這個時候需要使用響應式api,如:computed,computed傳回的是一個ref對象,需要取出其中的value來使用 。
五. 兄弟/任意元件
在Vue2.x中,兄弟元件或者任意兩個元件之間的傳值可以使用 $emit發送 和 $on接收 來實作,但在Vue3從執行個體中移除了 $on、$off 和 $once 方法,是以我們如果希望繼續使用全局事件總線,要通過第三方的庫:mitt 庫。
(1). 安裝mitt庫,生産依賴,并進行簡單封裝
【npm install mitt -S】
封裝為eventbus.js
import mitt from 'mitt';
const emitter = mitt();
export default emitter;
(2). 通過mitt庫中 emit 方法發送資訊,on方法接收資訊。 這兩個方法之間是通過其中的參數 key 來建立聯系的。
child1元件發送消息
<template>
<div>
我是child1元件哦
<button @click="mySend">測試發送啊</button>
</div>
</template>
<script>
import emitter from './utils/eventbus.js';
export default {
methods: {
mySend() {
console.log('child1元件點選發送')
// 發送1
emitter.emit('userInfo1', { name: 'lmr1', age: 20 });
// 發送2
emitter.emit('userInfo2', { name: 'lmr2', age: 100 });
}
}
}
</script>
child2元件接收消息(可以單個接收,也可以全部接收)
單個監聽
<script>
import emitter from './utils/eventbus.js';
export default {
created() {
// 1. 單個監聽
{
// 監聽1
emitter.on('userInfo1', (item) => {
console.log('userInfo1監聽到的内容如下:');
console.log(item);
});
// 監聽2
emitter.on('userInfo2', (item) => {
console.log('userInfo2監聽到的内容如下:');
console.log(item);
});
}
}
}
</script>
全部監聽
<script>
import emitter from './utils/eventbus.js';
export default {
created() {// 2. 全部監聽(類似周遊,監聽到1次,執行一次下面代碼)
emitter.on('*', (type, info) => {
console.log('下面是全部監聽哦:');
console.log(type);
console.log(info);
});
}
}
</script>
(3). 測試
(4). 補充-取消監聽
六. 對比Vue2.x的傳值方式
1. 父傳子
Vue2.x中的傳遞方式和Vue3.x中的相同,都是通過Props屬性傳遞。
2. 子傳父
和Vue3.x相同的是,Vue2.x也是通過 $emit對外傳遞方法,但是Vue2.x中可以不用事先通過emits屬性聲明,Vue2.x中不聲明不報警告,但是Vue3.x中不聲明,則報警告。
下面是子元件代碼:
<template>
<div>
<button @click="increment">增加</button>
<button @click="decrement">減少</button>
<button @click="cdMany">測試傳遞多個參數</button>
</div>
</template>
<script>
export default {
// Vue2.x中不涉及提前emits聲明,也不會報警告
// emits: ['addN', 'subN', 'cdN'],
data() {
return {};
},
methods: {
increment() {
this.$emit('addN', 2);
},
decrement() {
this.$emit('subN', 5);
},
// 傳遞多個參數
cdMany() {
this.$emit('cdN', 'ypf1', 20, '哈哈');
}
}
}
</script>
3. 爺傳孫
Vue2.x中沒有provide和inject選項。
4. 兄弟/任意元件
Vue2.x中提供 $emit對外發送函數 和 $on監聽函數。
封裝eventbus.js
import Vue from 'vue';
export default new Vue();
兄弟元件1-發送方
<template>
<div>
我是child1元件哦
<button @click="mySend">測試發送啊</button>
</div>
</template>
<script>
import vm from './utils/eventbus.js'
export default {
methods: {
mySend() {
console.log('child1元件點選發送')
// 發送1
vm.$emit('userInfo1', { name: 'lmr1', age: 20 });
// 發送2
vm.$emit('userInfo2', { name: 'lmr2', age: 100 });
}
}
}
</script>
兄弟元件2-監聽方
<template>
<div>
我是child2元件,我就接受消息哦。
</div>
</template>
<script>
import vm from './utils/eventbus.js'
export default {
mounted() {
// 1. 單個監聽
{
// 監聽1
vm.$on('userInfo1', (item) => {
console.log('userInfo1監聽到的内容如下:');
console.log(item);
});
// 監聽2
vm.$on('userInfo2', (item) => {
console.log('userInfo2監聽到的内容如下:');
console.log(item);
});
}
// 2. 全部監聽(沒有這種用法)
// 3.取消監聽,需要配合封裝函數
// vm.$off()
}
}
</script>
父元件
<template>
<div>
<!-- child1元件發送 -->
<child1></child1>
<!-- child2元件接收 -->
<child2></child2>
</div>
</template>
<script>
import child1 from './child1.vue';
import child2 from './child2.vue';
export default {
components: {
child1,
child2
},
data() {
return {};
}
}
</script>
!
- 作 者 : Yaopengfei(姚鵬飛)
- 部落格位址 : http://www.cnblogs.com/yaopengfei/
- 聲 明1 : 如有錯誤,歡迎讨論,請勿謾罵^_^。
- 聲 明2 : 原創部落格請在轉載時保留原文連結或在文章開頭加上本人部落格位址,否則保留追究法律責任的權利。