一、模組化與元件化
- 模組化的定義
模組化在Node中是一個規範,定義一些模組的相關的規則,從程式碼角度上來說,方便做區別,如果不使用模組化,寫在js檔案中不利於後期維護和擴充套件,從程式碼的層面上就把相關的功能脫離出來,所以模組化從從程式碼的角度觸發,分析專案,把專案中一些功能型別的程式碼,單獨抽離為一個個的模組,那麼為了保證大家以相同的方式去封裝模組,於是我們就創造了CommentJS規範
- 模組化的優點
在我們專案中,如果需要是實現相同的功能,就不需要再重寫,所以模組化從一定程度上提高我們的開發效率,有一些相關模組,直接呼叫就可以了,方便專案開發,和後期的維護與擴充套件
- 元件化:
把頁面中樣式差不多的東西抽為單獨的小元件,把需要經常複用的東西封裝為一個單獨的,今後需要用的時候直接拿就可以,不用再重寫,從ui的角度觸發去考慮問題,把頁面中程式碼結構類似的區域抽離出來,封裝成一個單獨的小元件 ;前端的元件化,方便UI元件的重用;
- 元件化的優點:
隨著專案規模的發展,我們手中的元件會越來越多,我們今後一個頁面的ui,幾乎都可以從手中拿現成的元件拼接出來,方便專案的開發和維護
二、建立全域性元件的方式
1. 建立全域性元件的方式一
- 先呼叫
Vue.extend()
得到元件的建構函式
var com1 = Vue.extend({
template: '<h2>這是建立的第一個全域性元件</h2>'
// template 屬性,表示這個元件的 UI 程式碼解構
})
- 通過
vue.component('元件的名稱',元件的建構函式)
來註冊全域性元件
Vue.component('mycom1', com1)
//com1就是元件的建構函式
注意:
元件的名稱如果是駝峰命名,那麼引入的時候表名稱得加連字元-
1.如果 Vue.component('myCom1','com1')
對應的元件標籤是
2. 如果是Vue.component('myCom1Test','com1')
對應元件標籤為:
3. 如果Vue.component('my-com1','com1')
對應元件標籤為:
- 把註冊好的元件名稱,以標籤的形式引入到vm例項區域的頁面中即可
<div id="app">
<!-- 引入全域性的vue元件-->
<mycom1></mycom1>
</div>
來吧展示:
2. 建立全域性元件的方式二
- 直接使用
vue.component('元件的名稱','元件物件')
// Vue.component 的第二個引數,既接收 一個 元件的建構函式, 同時,也接受 一個物件
Vue.component('mycom2', {
template:'<h2>這是直接使用 Vue.component 建立出來的元件</h2>'
})
- 把註冊好的元件名稱,以標籤的形式引入到vm例項區域的頁面中即可
<div id="app">
<mycom2></mycom2>
</div>
來吧展示:
注意:
1.template 屬性中,不能單獨放一段文字,必須用標籤包裹起來;
2. 如果在 template 屬性中,想要放多個元素了,那麼,在這些元素外,必須有唯一的一個根元素進行包裹;
Vue.component('mycom2', {
template:'<div><p>嘿嘿嘿嘿嘿</p><h2>這是直接使用 Vue.component 建立出來的元件</h2><h1>哈哈哈哈</h1> </div>'
})
3. 建立全域性元件的方式三
- 給
template
新增一個id選擇器
Vue.component('mycom3', {
template: '#tpl'
})
- 定義一個 template 標籤元素
使用 Vue 提供的 template 標籤,可以定義元件的UI模板解構
<div id="app">
<mycom3></mycom3>
</div>
<template id="tpl">
<h2>這是建立全域性元件的第三種方式</h2>
</template>
注意:
template標籤中裡面也必須有唯一的一個根元素進行包裹
也就是如果沒有根元素包裹,那麼下面程式碼是執行不出來了會報錯
<template id="tmpl">
<h2>這是建立全域性元件的第三種方式</h2>
<p>喲喲喲喲喲喲</p>
</template>
正確寫法:
<template id="tmpl">
<div>
<h2>這是建立全域性元件的第三中方式</h2>
<p>嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿</p>
</div>
</template>
既然是全域性元件,那麼就可以重複呼叫,栗子:
<div id="app">
<mycom3></mycom3>
</div>
<div id="app2">
<mycom3></mycom3>
</div>
<template id="tmpl">
<h2>這是建立全域性元件的第三中方式</h2>
</template>
<script>
Vue.component('mycom3', {
template: '#tmpl'
})
var vm = new Vue({
el: '#app',
});
var vm2 = new Vue({
el: '#app2',
});
</script>
三、建立私有元件
建立一個私有元件
<div id="app">
<mycom4></mycom4>
</div>
var vm = new Vue({
el: '#app',
data: {},
methods: {},
components: {
// 定義例項中私有元件的 元件的名稱 和元件的 解構
'mycom4': {
template: '<h6>這是定義的私有元件</h6>'
}
}
});
建立多個私有元件:
<div id="app">
<mycom4></mycom4>
<mycom5></mycom5>
</div>
components:{
mycom4:{
template:'<h2>這是我定義的私有元件1</h2>'
},
mycom5:{
template:'<h2>這是我定義的私有元件2</h2>'
}
}
四、元件中相應資料和展示方法
Vue.component('mycom', {
template: '<h3 @click="show">這是自定義的全域性元件 ------ {{ msg }}</h3>',
data: function () { //
// 在 元件中,可以有自己的私有資料
// 但是,元件的 data 必須是一個 function
// 並且內部 return 一個 資料物件
return {
msg: '我是元件的內部data'
}
},
methods: { // 嘗試定義元件的私有方法
show() {
// console.log('出發了元件的私有show方法!')
alert('我是元件內部的方法')
}
}
})
思考:
為什麼要把 元件中的 data 定義為一個function呢?
因為這樣做的話,每當我們在頁面上引用一次元件,必然會先呼叫 這個 data function,
從而得到一個當前元件私有的 資料物件;
五、切換元件
1. 結合flag識別符號和 v-if
與 v-else
實現元件的切換
<div id="app">
<!-- 使用按鈕去控制顯示login和res-->
<input type="button" value="顯示登入" @click="flag=true"/>
<input type="button" value="顯示註冊" @click="flag=false"/>
<login v-if="flag"></login>
<!-- 當flag:true的時候顯示login-->
<!-- 當flag:false的時候顯示res-->
<res v-else="flag"></res>
</div>
<script>
Vue.component('login', {
template: '<h2>登入</h2>'
})
Vue.component('res', {
template: '<h2>註冊</h2>'
})
// 建立 Vue 例項,得到 ViewModel
var vm = new Vue({
el: '#app',
data:{
flag:false
},
methods:{}
})
</script>
2. 切換多個元件
<div id="app">
<!--想要顯示哪個元件就在:is屬性的後面傳入(字串)=====> '元件的名字'-->
<component :is="'com1'"></component>
<component :is="'com3'"></component>
</div>
Vue.component('com1', {
template: '<h2>我是第1個元件</h2>'
})
Vue.component('com2', {
template: '<h2>我是第2個元件</h2>'
})
Vue.component('com3', {
template: '<h2>我是第3個元件</h2>'
})
Vue.component('com4', {
template: '<h2>我是第4個元件</h2>'
})
進行多元件的切換
<div id="app">
<!--點選a連結,修改component的值
component標籤結合is屬性進行元件的切換-->
<a href="#" @click="comname='com1'">顯示元件1</a>
<a href="#" @click="comname='com2'">顯示元件2</a>
<a href="#" @click="comname='com3'">顯示元件3</a>
<a href="#" @click="comname='com4'">顯示元件4</a>
<component :is="comname"></component>
</div>
var vm = new Vue({
el: '#app',
data:{
comname:'com1'
},
//當vue解析檔案到component標籤時,如果有:is屬性就會解析後面的字串"comname"
//然後去data中尋找這個變數
//comname:'com1'
//正好是一個字串的變數的名稱,就會顯示名稱叫com1的元件
methods:{}
})
3.為元件切換新增動畫
<transition>
<component :is="comname"></component>
</transition>
<style>
.v-enter,
.v-leave-to{
opacity:0;
transform: translate(100px);
}
.v-enter-active,
.v-leave-active{
transition: all 0.4s ease;
}
</style>
如上圖效果顯示,有標準流的影響,所以要脫離標準流的影響,讓離開的元件脫離標準流
<style>
.....
.v-enter-active,
.v-leave-active{
transition: all 0.4s ease;
position: absolute;
}
</style>
如圖動畫效果是先進入再離開,如果想要實現先離開再進入,則只需要在transition
中新增mode="out-in"
<transition mode="out-in"> -
<component :is="comname"></component>
</transition>
如果想要實現離開往左走,進入往右走的效果,則:
<style>
.v-enter {
/* 即將進入時候的座標 */
opacity: 0;
transform: translateX(100px);
}
.v-leave-to {
/* 離開時候,最終到達的位置 */
opacity: 0;
transform: translateX(-100px);
}
</style>
六、父元件通過屬性繫結向子元件傳遞資料
- 把要傳遞給子元件的資料,作為自定義屬性,通過
v-bind
繫結到子元件身上
<com :sonmsg="pmsg"></com>
- 在子元件中,不能直接使用父元件傳遞過來的資料,需要先用
props
來接收一下
props: ['sonmsg']
- 在接收父元件傳遞過來的
props
的時候,一定要和父元件中傳遞過來的自定義屬性名稱保持一致
template: '<h2>我是子元件-----{{sonmsg}}</h2>',
具體程式碼如下:
<body>
<div id="app">
<com :sonmsg="pmsg"></com>
<!-- 以屬性繫結的方式將父元件中的值傳遞給子元件-->
<!-- 這裡相當於把 '我是父元件中的資料'放在這邊 也就是 msg123='我是父元件中的資料'-->
<!-- 但是如果子元件想用msg需要在子元件中定義一下-->
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
pmsg:'我是父元件中的資料'
},
methods: {},
components: { // 定義私有元件
'com': { // 在Vue中,預設,子元件無法直接獲取父元件中的資料
template: '<h2>我是子元件-----{{sonmsg}}</h2>',
props: ['sonmsg']
// 在Vue中,只有 props 是陣列,其它帶 s 字尾的屬性都是 物件
}
}
});
</script>
</body>
七、父元件向子元件傳遞物件
- 把要傳遞給子元件的物件,作為自定義屬性,通過
v-bind
繫結到子元件身上
<com1 :msgobj123="msgObj"></com1>
- 在子元件中,不能直接使用父元件傳遞過來的物件,需要先用
props
來接收一下
props: ['msgobj123']
- 在接收父元件傳遞過來的
props
的時候,一定要和父元件中傳遞過來的自定義屬性名稱保持一致
template: '<h3>後面傳遞的是父元件中物件 ---- {{ JSON.stringify(msgobj123) }}</h3>'
template: '<h3>哈哈 {{ JSON.stringify(msgobj) }}</h3>',
具體程式碼如下:
<body>
<div id="app">
<com1 :msgobj123="msgObj"></com1>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
msgObj: {
id:1,
name:'千夏Chinatsu',
age:18
}
},
methods: {},
components: {
'com1': {
template: '<h3>後面傳遞的是父元件中物件 ---- {{ JSON.stringify(msgobj123) }}</h3>',
props: ['msgobj123']
}
}
});
</script>
</body>
八、父元件向子元件傳遞方法
- 把要傳遞給子元件的方法,通過
v-on
繫結事件到子元件身上
<com v-on:func="show()"></com>
- 在子元件中,不能直接使用父元件傳遞過來的方法,需要先用
$emit()
來接收一下
this.$emit('func')
- 在接收父元件傳遞過來的
$emit()
中,一定要和父元件中傳遞過來的方法名稱保持一致
具體程式碼:
<body>
<div id="app">
<com v-on:func="show()"></com>
</div>
<script>
var vm = new Vue({
el:'#app',
data:{},
methods:{
show(){
console.log('觸發了父元件中的show()方法')
}
},
components: {
'com': {
template: '<input type="button" value="這是子元件的按鈕" @click="btnClick()"/>',
methods:{
btnClick(){
// console.log('hhhh')
this.$emit('func')
}
}
}
}
})
</script>
</body>
總結:
1.如果要向子元件傳遞 data 中的資料,則 使用 屬性繫結的形式v-bind:
2. 如果要向子元件傳遞 methods 中的 方法,則 使用 事件繫結的形式v-on:
九、子元件向父元件傳遞資料
<body>
<div id="app">
<!-- 方式一:-->
<com v-on:func="show"></com>
<!-- $emit('func',1)後面要傳遞引數-->
<!-- 方式二:-->
<!-- <com v-on:func="show(2)"></com>-->
<!-- 然後$emit('func')後面就不用傳遞引數-->
</div>
<script>
var vm = new Vue({
el:'#app',
data:{},
methods:{
show(arg){
console.log('觸發了父元件中的show()方法' + arg)
// '--------'
}
},
components: {
'com': {
template: '<input type="button" value="這是子元件的按鈕" @click="btnClick()"/>',
data:function(){
return{
sonmsg:'這是子元件中的資料'
}
},
methods:{
btnClick(){
this.$emit('func','嘿嘿嘿嘿嘿')
}
}
}
}
})
</script>
</body>
所以可以直接在show()方法中傳入子元件中的data資料
methods:{
show(arg){
console.log('觸發了父元件中的show()方法' +'--------'+ arg)
// '--------'
}
},
components: {
'com': {
template: '<input type="button" value="這是子元件的按鈕" @click="btnClick()"/>',
data:function(){
return{
sonmsg:'這是子元件中的資料'
}
},
methods:{
btnClick(){
// console.log('hhhh')
this.$emit('func','嘿嘿嘿嘿嘿')
// this.$emit('func',this.sonmsg)
}
}
}
}
把子元件傳遞過來的資料,儲存到 父元件的 data 中
methods: {
show(arg) {
// console.log('觸發了父元件中的show()方法' +'--------'+ arg)
// 把子元件傳遞過來的資料,儲存到 父元件的 data 中
this.msgFormSon = arg
console.log(this.msgFormSon)
}
},
總結:
子元件向父元件傳值,本質上,還是呼叫了父元件傳遞過來的方法
只不過,子元件在呼叫的時候,把 資料 當作引數,傳給這個方法了;
十、練習列表案例(結合父子元件傳值)
<body>
<div id="app">
<!-- 評論框區域 -->
<cmt-box @func="addNewCmt"></cmt-box>
<ul>
<cmt-item v-for="(item, i) in list" :item="item" :key="i"></cmt-item>
</ul>
</div>
<script>
Vue.component('cmt-item', {
template: `<li>
<h3>評論人:{{ item.name }}</h3>
<h5>評論內容:{{ item.content }}</h5>
</li>`,
props: ['item']
})
Vue.component('cmt-box', {
template: `<div>
<label>評論人:</label>
<br>
<input type="text" v-model="name">
<br>
<label>評論內容:</label>
<br>
<textarea v-model="content"></textarea>
<br>
<input type="button" value="發表評論" @click="postComment">
</div>`,
data: function () {
return {
name: '',
content: ''
}
},
methods: {
postComment() { // 發表評論
// console.log('ok')
const cmt = { name: this.name, content: this.content }
// 子元件中,呼叫父元件傳遞過來的方法,然後可以把 子元件的資料,當作引數,傳遞給父元件的方法去使用
this.$emit('func', cmt)
this.name = this.content = ''
// console.log(cmt)
}
}
})
var vm = new Vue({
el: '#app',
data: {
list: [
{ name: 'zs', content: '沙發' },
{ name: 'ls', content: '板凳' },
{ name: 'qqq', content: '涼蓆' },
{ name: 'eee', content: '磚頭' }
]
},
methods: {
addNewCmt(cmt) { // 新增新評論
// console.log(cmt)
this.list.push(cmt)
}
}
});
</script>
</body>
十一、使用rel屬性來獲取頁面中的元素
<body>
<div id="app">
<input value="按鈕" type="button" @click="show()"/>
<!--<h2 id="myh2">{{msg}}</h2>-->
<!--加入ref屬性-->
<h2 id="myh2" ref="hhh">{{msg}}</h2>
</div>
<script>
var vm = new Vue({
el:'#app',
data:{
msg:'嘿嘿嘿嘿嘿'
},
methods:{
show(){
//原生想要獲取h2中的資料的方法
// var res = document.getElementById('myh2').innerHTML
//console.log(res)
console.log(this)
console.log(this.$refs.hhh)
console.log(this.$refs.hhh.innerHTML)
}
}
})
</script>
</body>
在h2標籤中沒有加入ref
屬性的列印console.log(this)
結果
在h2標籤加入ref
屬性的列印console.log(this)
結果
所以可以通過rel
可以很方便的來獲取元素
console.log(this)
console.log(this.$refs.hhh)
console.log(this.$refs.hhh.innerHTML)
十二、使用rel屬性來獲取頁面中的元件
所以可以根據msg去修改元件內部的資料或者呼叫子元件中的方法
<body>
<div id="app">
<input value="按鈕" type="button" @click="getCom()" />
<com1 ref="xxxxx"></com1>
</div>
<script>
Vue.component('com1', {
template:'<h2>這是一個小元件---{{msg}}</h2>',
data:function () {
return {
msg:'這是元件內部資料'
}
},
methods:{
show(){
console.log('子元件中的方法被呼叫了')
}
}
})
var vm = new Vue({
el:'#app',
data:{
msg:'這是父元件的資料'
},
methods:{
getCom(){
// console.log(this)
this.$refs.xxxxx.msg = '元件內部資料被修改了'
this.$refs.xxxxx.show()
}
}
})
//頁面上可以為很多元素建立ref的引用
</script>
</body>
十三、在vue元件中data和props的區別
data
在元件中,要被定義成一個function,並且要返回一個物件props
在元件中,要被定義成陣列,其中,陣列的值都是字串名,表示從父元件傳遞過來的資料props
中的資料,不要直接拿來修改,如果想要修改,必須在data上重新定義一個屬性,然後把屬性的值從this.props
直接拿過來data
上的資料,都是元件自己私有的,資料都是可讀可寫的props
都是外界傳遞過來的資料,資料只能讀取,不能重新寫入