1.watch如何深度監聽,watch監聽引用類型數據,拿不到oldVal
<template>
<div>
<input v-model="name"/>
<input v-model="info.city"/>
</div>
</template>
<script>
export default {
data() {
return {
name: '雙越',
info: {
city: '北京'
}
}
},
watch: {
name(oldVal, val) {
// eslint-disable-next-line
console.log('watch name', oldVal, val) // 值類型,可正常拿到 oldVal 和 val
},
info: {
handler(oldVal, val) {
// eslint-disable-next-line
console.log('watch info', oldVal, val) // 引用類型,拿不到 oldVal 。因為指針相同,此時已經指向了新的 val
},
deep: true // 深度監聽,可以監聽到引用類型中的屬性city。
}
}
}
</script>
2. v-if和v-show
跟新不是很頻繁,用v-if,
跟新很頻繁,用v-show,利用的display:none
3,v-for 循環遍歷,key的重要性,v-for 和v-if是不能一起使用
加了key(一定要具有唯一性),vue中列表循環需加:key="唯一標識" 唯一標識可以是item里面id index等,因為vue組件高度復用增加Key可以標識組件的唯一性,為了更好地區別各個組件 key的作用主要是為了高效的更新虛擬DOM
<template>
<div>
<p>遍歷數組</p>
<ul>
<li v-for="(item, index) in listArr" :key="item.id">
{{index}} - {{item.id}} - {{item.title}}
</li>
</ul>
<p>遍歷對象</p>
<ul v-if="flag">
<!-- v-if不能和v-for在同一個標簽使用,v-for渲染模板的優先級比v-if高,遍歷一遍v-if判斷一次,效率不高,在 在父級容器加個v-if判斷即可 -->
<li v-for="(val, key, index) in listObj" :key="key">
{{index}} - {{key}} - {{val.title}}
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
flag: false,
listArr: [
{ id: 'a', title: '標題1' }, // 數據結構中,最好有 id ,方便使用 key
{ id: 'b', title: '標題2' },
{ id: 'c', title: '標題3' }
],
listObj: {
a: { title: '標題1' },
b: { title: '標題2' },
c: { title: '標題3' },
}
}
}
}
</script>
4. 事件, event, 事件修飾符, 事件綁定到哪里
在Vue中,事件修飾符處理了許多DOM事件的細節,讓我們不再需要花大量的時間去處理這些煩惱的事情,而能有更多的精力專注於程序的邏輯處理。在Vue中事件修飾符主要有:
.stop:等同於JavaScript中的event.stopPropagation(),防止事件冒泡
.prevent:等同於JavaScript中的event.preventDefault(),防止執行預設的行為(如果事件可取消,則取消該事件,而不停止事件的進一步傳播)
.capture:與事件冒泡的方向相反,事件捕獲由外到內
.self:只會觸發自己范圍內的事件,不包含子元素
.once:只會觸發一次


<template>
<div>
<p>{{num}}</p>
<button @click="increment1">+1</button>
<button @click="increment2(2, $event)">+2</button>
</div>
</template>
<script>
export default {
data() {
return {
num: 0
}
},
methods: {
increment1(event) {
console.log('event', event, event.__proto__.constructor) // 是原生的 event 對象
//event.target 事件掛載到那個節點上
console.log(event.target)
console.log(event.currentTarget) // 注意,事件是被注冊到當前元素的,和 React 不一樣
this.num++
// 1. event 是原生的
// 2. 事件被掛載到當前元素
// 和 DOM 事件一樣
},
increment2(val, event) {
// eslint-disable-next-line
console.log(event.target)
this.num = this.num + val
},
loadHandler() {
// do some thing
}
},
mounted() {
window.addEventListener('load', this.loadHandler)
},
beforeDestroy() {
//【注意】用 vue 綁定的事件,組建銷毀時會自動被解綁 // 自己綁定的事件,需要自己銷毀!!!
window.removeEventListener('load', this.loadHandler)
}
}
</script>
5. v-model,常見表單項, textarear checkbox, radio, select,
修飾符, lazy number trim
<template>
<div>
<p>輸入框: {{name}}</p>
<!-- 修飾符trim,清除前后空格 -->
<input type="text" v-model.trim="name"/>
<!-- 修飾符lazy,只有在input輸入框發生一個blur時才觸發 -->
<input type="text" v-model.lazy="name"/>
<!-- 修飾符number, 將用戶輸入的字符串轉換成number -->
<input type="text" v-model.number="age"/>
<p>多行文本: {{desc}}</p>
<textarea v-model="desc"></textarea>
<!-- 注意,<textarea>{{desc}}</textarea> 是不允許的!!! -->
<p>復選框 {{checked}}</p>
<input type="checkbox" v-model="checked"/>
<p>多個復選框 {{checkedNames}}</p>
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
<p>單選 {{gender}}</p>
<input type="radio" id="male" value="male" v-model="gender"/>
<label for="male">男</label>
<input type="radio" id="female" value="female" v-model="gender"/>
<label for="female">女</label>
<p>下拉列表選擇 {{selected}}</p>
<select v-model="selected">
<option disabled value="">請選擇</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<p>下拉列表選擇(多選) {{selectedList}}</p>
<select v-model="selectedList" multiple>
<option disabled value="">請選擇</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
</div>
</template>
<script>
export default {
data() {
return {
name: '雙越',
age: 18,
desc: '自我介紹',
checked: true,
checkedNames: [],
gender: 'male',
selected: '',
selectedList: []
}
}
}
</script>
6.props, $emit, 組件通訊,自定義事件
父子傳遞,自定義事件
Vue兄弟組件之間通信 eventBus
新建event.js,兄弟組件映入該組件,兄弟組件通過event.$on, 或者event.$emit來通信
import Vue from 'vue' export default new Vue()
或者在main.js中設置全局事件總線,然后兄弟組件this.$bus.$on, this.$bus.$emit來通信
// new Vue()實例化了一個Vue的實例化對象 //因為只有組件對象或者Vue的實例化對象才能調用$on和$emit //想要成為事件總線的條件: //1、所有的組件對象必須都能看得到這個總線對象,因此我們把這個對象放在了Vue原型 //2、這個事件總線對象必須能調用$on和$emit方法(總線對象必須是Vue的實例化對象或者是組件對象) new Vue({ beforeCreate(){ Vue.prototype.$bus = this }, el:'#root', render: h => h(App) })
父組件
<template>
<div>
<Input @add="addHandler"/>
<List :list="list" @delete="deleteHandler"/>
</div>
</template>
<script>
import Input from './Input'
import List from './List'
export default {
components: {
Input,
List
},
data() {
return {
list: [
{
id: 'id-1',
title: '標題1'
},
{
id: 'id-2',
title: '標題2'
}
]
}
},
methods: {
addHandler(title) {
this.list.push({
id: `id-${Date.now()}`,
title
})
},
deleteHandler(id) {
this.list = this.list.filter(item => item.id !== id)
}
},
created() { // eslint-disable-next-line
console.log('index created')
},
mounted() {
// eslint-disable-next-line
console.log('index mounted')
},
beforeUpdate() {
// eslint-disable-next-line
console.log('index before update')
},
updated() {
// eslint-disable-next-line
console.log('index updated')
},
}
</script>
子組件input
<template>
<div>
<input type="text" v-model="title"/>
<button @click="addTitle">add</button>
</div>
</template>
<script> import event from './event'
export default {
data() {
return {
title: ''
}
},
methods: {
addTitle() {
// 調用父組件的事件
this.$emit('add', this.title)
// 調用自定義事件
event.$emit('onAddTitle', this.title) this.title = ''
}
}
}
</script>
子組件List
<template>
<div>
<ul>
<li v-for="item in list" :key="item.id">
{{item.title}}
<button @click="deleteItem(item.id)">刪除</button>
</li>
</ul>
</div>
</template>
<script> import event from './event'
export default {
// props: ['list']
props: {
// prop 類型和默認值
list: { type: Array, default() { return [] }
}
},
data() {
return {
}
},
methods: {
deleteItem(id) {
this.$emit('delete', id)
},
addTitleHandler(title) { // eslint-disable-next-line
console.log('on add title', title)
}
},
created() {
// eslint-disable-next-line
console.log('list created')
},
mounted() {
// eslint-disable-next-line
console.log('list mounted')
// 綁定自定義事件
event.$on('onAddTitle', this.addTitleHandler)
},
beforeUpdate() {
// eslint-disable-next-line
console.log('list before update')
},
updated() {
// eslint-disable-next-line
console.log('list updated')
},
beforeDestroy() {
// 及時銷毀,否則可能造成內存泄露
event.$off('onAddTitle', this.addTitleHandler)
}
}
</script>
父子組件生命周期的順序, 父組件created創建了實例,子組件list也創建了實例,並且mounted渲染了模板,然后父組件才mounted渲染模板
子組件更新完,父組件才會更新完
生命周期過程;https://www.cnblogs.com/fsg6/p/14468597.html

