Vue組件化通訊
1. Vue的組成文件(.vue)
分為三部分,分別對(duì)應(yīng)html,js,css
- <template></template>
- <script></script>
- <style></style>
2. Vue的生命周期函數(shù)(watch的時(shí)候dom也沒(méi)有更新)
- beforeCreate() 創(chuàng)建數(shù)據(jù)之前
- created() 創(chuàng)建數(shù)據(jù) 我們?cè)谶@里的得到我們?cè)赿ata里面創(chuàng)建的數(shù)據(jù)
- beforeMount() // Dom渲染完成前
- mounted() //Dom渲染完成
- beforeUpdate() // 更新視圖 在beforeUpdate觸發(fā)時(shí),視圖已經(jīng)更新完成
- Updated() //更新數(shù)據(jù)調(diào)用的函數(shù)、。
<div id='app'>
<p>{{msg}}</p>
<input type='text' v-model='msg'>
</div>
var app = new Vue({
el: '#app',
data() {
return {
msg: 1
}
},
beforeCreate() {
console.log('beforeCreate', this.msg); //beforeCreate undefined
console.log('beforeCreate: ', document.getElementsByTagName('p')[0]) //beforeCreate <p>{{msg}}</p>
},
created() {
// 創(chuàng)建數(shù)據(jù)
console.log('created', this.msg); //beforeCreate 1
console.log('created: ', document.getElementsByTagName('p')[0]) //beforeCreate <p>{{msg}}</p>
// 異步處理得到渲染的dom數(shù)據(jù)
setTimeout(() => {
this.msg = 100
console.log('nextTick', document.getElementsByTagName('p')[0])
}, 100)
// nextTick <p>100</p>
},
beforeMount() {
console.log('beforeMount', this.msg) //beforeMount 1
console.log('beforeMount: ', document.getElementsByTagName('p')[0]) // beforeMount <p>{{msg}}</p>
},
mounted() {
// 渲染dom
console.log('mounted', this.msg) //mounted 1
console.log('mounted: ', document.getElementsByTagName('p')[0]) //mounted <p>1</p>
},
beforeUpdate() {
console.log('beforeUpdate', this.msg) //beforeUpdate 100
console.log('beforeUpdate: ', document.getElementsByTagName('p')[0]) //beforeUpdate <p>100</p>
},
updated() {
console.log('updated', this.msg) // updated 1
console.log('updated: ', document.getElementsByTagName('p')[0]) // updated <p>100</p>
}
})
3. export default
每一個(gè)模塊都是自己的作用域,相應(yīng)的屬性來(lái)處理數(shù)據(jù)和函數(shù)
- data(聲明數(shù)據(jù),可以是函數(shù)和屬性)
-
類型:
Object | Function
- 組件只接受函數(shù)
// 對(duì)象的形式
export default{
data: {
a:1
}
}
// 函數(shù)的形式
export default{
data(){
return {
a: 1
}
}
}
- methods(一些指令和其他屬性的調(diào)用方法)
- 不要用箭頭函數(shù)來(lái)寫(xiě)里面的函數(shù)
- this指向Vue的實(shí)例
export default{
methods: {
plus() {
this.a++
}
}
}
- components (組件化定義)
-
類型:
Object
- 自定義元素,增加代碼的復(fù)用性
-
類型:
// 當(dāng)我們引用一個(gè).vue文件的時(shí)候,就像使用這個(gè)文件來(lái)充當(dāng)我們主體的一部分
<div>
<hello></hello>
</div>
import hello from './hello.vue'
export default {
components: {
hello
}
}
-
computed(計(jì)算屬性)
- 計(jì)算屬性的結(jié)果會(huì)被緩存,依賴的數(shù)據(jù)發(fā)生變化才會(huì)重新渲染
- 注意計(jì)算屬性和methods,watch的區(qū)別
{{this.total}} //[3,4] <button @click='add'>添加數(shù)據(jù)</button> //點(diǎn)擊會(huì)更新this.total export default { data: () => ({ a: 1, b: [2,3] }), methods: { add(){ this.b.push(8); } }, computed: { total(){ return this.b.map((item)=>{ return item+this.a }) } } }
-
watch(監(jiān)聽(tīng)對(duì)應(yīng)的數(shù)據(jù))
- 鍵值對(duì)。鍵是我們需要監(jiān)督的數(shù)據(jù),值是相應(yīng)的回調(diào)函數(shù)
- 回調(diào)函數(shù)接受2個(gè)參數(shù),新的值和舊的值(對(duì)于數(shù)組和對(duì)象不會(huì)出現(xiàn)舊值,對(duì)于簡(jiǎn)單的數(shù)據(jù)會(huì)出現(xiàn)舊值)
- 監(jiān)聽(tīng)對(duì)象的內(nèi)部值變化,需要添加deep:true(數(shù)組不用)
// 點(diǎn)擊后相應(yīng)的變化 data(){ return { a: 1, b: [2,4,6], c:{name:'hcc',age:22} } }, methods: { add(){ this.a++ this.b.push(8) this.c.name = 'yx' } }, watch: { b: function(val, oldVal){ console.log('new', val) //[2,4,6,8] console.log('new', oldVal) //[2,4,6,8] }, a: function(val, oldVal){ console.log(val); //2 console.log(oldVal); //1 }, c:{ handler(val){ console.log(val); //{name: 'yx',age: 22} } } },
-
props(用于接受父組件傳來(lái)的數(shù)據(jù))
- 規(guī)定和接受父組件的數(shù)據(jù)
- 單向數(shù)據(jù)流,子組件不能修改傳遞過(guò)來(lái)的數(shù)據(jù)
- 對(duì)象和數(shù)組是引用類型,指向同一個(gè)內(nèi)存空間,如果 prop 是一個(gè)對(duì)象或數(shù)組,在子組件內(nèi)部改變它會(huì)影響父組件的狀態(tài)。
- 可以規(guī)定接受的數(shù)據(jù)類型和默認(rèn)值,如果是對(duì)象和數(shù)組,默認(rèn)值導(dǎo)出是一個(gè)函數(shù)
// 父組件 <hello :formParent='num'></hello> //html components: { hello }, data(){ return { num: 3 } } //子組件 //1. 數(shù)組規(guī)定接受的數(shù)據(jù) props: ['hello'] //2. 驗(yàn)證的方式 props:{ hello: Number, hello: [String, Number], hello: { type: Object, default(){ return {message: 'hello'} } } }
-
v-on和v-emit(子組件向父元素傳遞數(shù)據(jù))
-
vm.$emit: 子元素向父元素定義訊號(hào)和傳遞數(shù)據(jù)
this.$emit('規(guī)定的訊號(hào)名稱', '想傳遞給父元素的數(shù)據(jù)')
-
vm.$on: 監(jiān)聽(tīng)訊號(hào),并觸發(fā)相應(yīng)的函數(shù)(函數(shù)內(nèi)部不用傳參)
@'規(guī)定的訊號(hào)名稱'='調(diào)用自己組件的方法并可以接受傳遞的參數(shù)'
// 子組件 data () { return { msg: 'Welcome to Your Vue.js App' } }, methods: { change(){ this.$emit('sendMsg',this.msg) //把msg傳遞給父組件 } } // 父組件 // 引入子組件,并定義components components: { hello }, methods: { show(msg){ // 這里接受子組件傳遞的參數(shù) console.log(msg); } } <hello @sendMsg='show'></hello> // 這里不用傳遞參數(shù),不然會(huì)覆蓋子元素傳遞的參數(shù)
-
-
ref(用來(lái)獲取dom和子組件)
可以用來(lái)操作dom
<p ref="p">hello</p>
可以用來(lái)組件中的通訊
-
在組件中使用的this.refs是一個(gè)對(duì)象,包含了所有的綁定了的dom和子組件
// html <h1 ref="myElement">這是一個(gè)dom元素</h1> //dom元素 <hello :propnum="propnum" :obj='d' @getson='getMsg' ref='child'></hello> // 子組件 >-- 組件中this.refs => {myElement: h1, child: VueComponent} // 運(yùn)用(在父元素中調(diào)用子元素的方法) // html <hello ref='child'></hello> // 子元素hello methods: { change() { this.$emit('getson',this.msg) this.obj.name = 'yx' }, drop(el) { el.style.background = 'red'; } }, // 父元素 methods: { add() { console.log(this.refs); //{child: VueComponent} this.$refs.child.drop('這里傳遞父元素的dom節(jié)點(diǎn)') } } //如果有一個(gè)需求是,一個(gè)父元素有2個(gè)子組件,其中一個(gè)子組件的方法要調(diào)用另一個(gè)子組件的dom元素 1. 一個(gè)子組件需要向父組件發(fā)送元素this.$emit('方法名',dom) 2. 父元素接受到子組件的傳遞得到對(duì)應(yīng)dom 3. 父元素通過(guò)this.$refs調(diào)用對(duì)應(yīng)的另一個(gè)子組件的方法并傳入?yún)?shù) // 子元素hello和world <div class="world"> <h1 ref="world">這是world的dom元素</h1> <button @click='send'>給父元素傳遞dom</button> </div> methods: { send(){ this.$emit('give',this.$refs.world); //給父元素發(fā)送dom } <div class='hello'> <button>改變dom</button> </div> methods: { changeDom(target){ console.log(target) } } // 父元素 <world @give='父親自己的方法'></world> <hello ref='helloChild'></hello> methods: { // 這里接受子元素傳遞過(guò)來(lái)的dom元素 '父親自己的方法'(target) { this.refs.helloChild.changeDom(target) //調(diào)用另一個(gè)子元素的方法,并把dom傳遞過(guò)去 } }
-
vm.nextTick(callback)
下次dom更新循環(huán)結(jié)束后執(zhí)行對(duì)應(yīng)的回調(diào)函數(shù)
在修改數(shù)據(jù)之后立即使用這個(gè)方法,可以獲取更新后的DOM結(jié)構(gòu)
- 使用場(chǎng)景
- 在 Vue 生命周期的 created() 鉤子函數(shù)進(jìn)行的 DOM 操作一定要放在 Vue.nextTick() 的回調(diào)函數(shù)中。原因是什么呢,原因是
在 created() 鉤子函數(shù)執(zhí)行的時(shí)候 DOM 其實(shí)并未進(jìn)行任何渲染,而此時(shí)進(jìn)行 DOM 操作無(wú)異于徒勞,所以此處一定要將 DOM 操作的 js 代碼放進(jìn) Vue.nextTick() 的回調(diào)函數(shù)中。
與之對(duì)應(yīng)的就是 mounted 鉤子函數(shù),因?yàn)樵撱^子函數(shù)執(zhí)行時(shí)所有的 DOM 掛載和渲染都已完成,此時(shí)在該鉤子函數(shù)中進(jìn)行任何DOM操作都不會(huì)有問(wèn)題 。 - 在數(shù)據(jù)變化后要執(zhí)行的某個(gè)操作,而這個(gè)操作需要使用隨數(shù)據(jù)改變而改變的 DOM 結(jié)構(gòu)的時(shí)候,這個(gè)操作都應(yīng)該放進(jìn) Vue.nextTick() 的回調(diào)函數(shù)中。
- 在 Vue 生命周期的 created() 鉤子函數(shù)進(jìn)行的 DOM 操作一定要放在 Vue.nextTick() 的回調(diào)函數(shù)中。原因是什么呢,原因是
// 需求一,如果我們想異步請(qǐng)求數(shù)據(jù)后,在鉤子函數(shù)mounted之前只用對(duì)應(yīng)的dom
// 思路: 通過(guò)異步等dom更新后,然后獲得對(duì)應(yīng)的dom
<template>
<h1 ref='title'>{{b}}</h1>
</template>
<script>
export default {
data() {
b: 'hello nextTick'
},
create() {
console.log(this.refs.title) // undefined
},
// 這樣可以獲得對(duì)應(yīng)的dom (當(dāng)dom全部渲染后再執(zhí)行console.log())
// create() {
// this.$nextTick(()=>{
// console.log(this.refs.title); // <h1>hello nextTick</h1>(輸出在mounted的后面)
// })
// },
mounted() {
console.log(this.refs.title) // <h1>hello nextTick</h1>
}
}
</script>
?