5.1数据相关api
5.1.1 Vue.set
向响应式对象中添加一个属性,并且确保这个新的属性同样是响应式的,且触发视图更新
使用方法:
Vue.set(target,propertyName/index,value)
<template>
<div id="app">
<!-- vue.set -->
<p>
<input v-model.number="price"/>
<button @click="batchUpdate">批量更新价格</button>
</p>
<div class="course-list">
<div v-for="c in courses" :key="c.name">
{{c.name}}-¥{{c.price}}
</div>
</div>
</div>
</template>
<script>
import Vue from 'vue'
export default {
name:"App",
data(){
return{
courses:[],
price:0
}
},
methods:{
getCourses(){
return new Promise(resolve=>{
setTimeout(()=>{
resolve([{ name: 'web全栈' }, { name: 'web高级' }])
},2000)
})
},
batchUpdate(){
this.courses.forEach(c=>{
Vue.set(c,'price',this.price)
})
}
},
async created(){
const courses =await this.getCourses();
this.courses = courses
}
}
5.1.2 Vue.delete
删除对象属性,如果对象是响应式的,确保删除能触发更新视图
Vue.delete(target,propertyName/index)
5.2事件相关api
5.2.1 Vm.$on
监听当前实例的自定义事件。事件可以由vm.$emit触发,回调函数会接收所有传入事件事件触发函数的额外参数
vm.$on('test',function(msg){
console.log(msg)
})
5.2.2 Vm.$emit
触发当前实例上的事件,附加参数都会传给监听器回调
vm.$emit('test','hi')
事件总线
通过在Vue原型上添加一个Vue实例作为事件总线,实现组件间相互通信,而且不受组件间关系的影响
vue.prototype.$bus = new Vue()
这样做可以在任何组件中使用this.$bus访问到该组件实例
<template>
<div id="app">
<!-- 监听事件 -->
<course-add v-model="course" @add-course="addCourse"></course-add>
<!-- 组件化 -->
<course-list :courses="courses" @add-course="addCourse"></course-list>
<!-- 增加success样式 -->
<message :show.sync="show" class="success">...</message>
<message :show.sync="showWarn" class="warnning">
<template v-slot:title>
<strong>警告</strong>
</template>
<template v-slot:default>
请输入课程名称!
</template>
</message>
</div>
</template>
<script>
import Vue from 'vue'
Vue.config.productionTip = false
Vue.component('course-list',{
data(){
return {
selectedCourse:'',
}
},
props:{
courses:{
type:Array,
default:()=>[]
}
},
template:`
<div>
<p v-if="courses.length==0">没有任何课程信息</p>
<ul>
<!-- class绑定 -->
<li v-for="(item,index) in courses" :key=index :class="{active:(selectedCourse===index)}" @click="selectedCourse=index">{{item}}</li>
<!--style绑定 -->
<!--<li v-for="(item,index) in courses" :key=index :style="{backgroundColor:(selectedCourse===index)?'#ddd':'transparent'}" @click="selectedCourse=index">{{item}}</li>-->
</ul>
</div>
`
})
Vue.component('course-add',{
props:['value'],
template:`
<div>
<!--表单输入绑定-->
<input :value="value" @input="onInput" @keydown.enter="addCourse"/>
<!--事件处理-->
<button v-on:click="addCourse">新增课程</button>
</div>
`,
methods:{
addCourse(){
// this.$emit('add-course',this.course);
//this.course =''
this.$emit('add-course')
},
onInput(e){
this.$emit('input',e.target.value)
}
}
})
Vue.component('message',{
props:['show'],
template:`
<div class="message-box" v-if="show">
<strong><slot name="title"></slot></strong>
<slot></slot>
<span class="message-box-close" @click="$emit('update:show',false)">X</span>
</div>
`,
mounted(){
//监听关闭事件
this.$bus.$on('message-close',()=>{
this.$emit('update:show',false)
})
}
})
export default {
name:"App",
data(){
return{
courses:[],
course:"",
selectedCourse:'',//选中项
show:false,
showWarn:false,
}
},
methods:{
addCourse(){
if(this.course!=""){
this.show = true
this.courses.push(this.course)
this.course = ''
}else{
this.showWarn = true
}
},
getCourses(){
return new Promise(resolve=>{
setTimeout(()=>{
// resolve(['web全栈','Web高级'])
resolve([{ name: 'web全栈' }, { name: 'web高级' }])
},2000)
})
},
batchUpdate(){
this.courses.forEach(c=>{
Vue.set(c,'price',this.price)
})
}
},
async created(){
const courses =await this.getCourses();
this.courses = courses
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
.message-box{
padding:10px 20px;
background:#4fc08d;
border:1px solid #42b983
}
.success{
background:#4fc08d;
border:1px solid #42b983;
}
.warning{
background:#f66;
border:1px solid #d63200;
}
</style>
<!--派发关闭事件-->
<div class="toolbar">
<button @click="$bus.$emit('message-close')"></button>
</div>
5.2.3 Vm.$once
监听一个自定义事件,但是只触发一次,一旦触发之后,监听器就会被移除
vm.$once('test',function(msg){
console.log(msg)
})
5.2.4 Vm.$off
移除自定义事件的监听器
如果没有提供参数,则移除所有事件的监听器
如果提供了事件,则移除该事件所有的监听器
如果同时提供了事件与回调,则只移除这个回调的监听器
vm.$off()//移除所有的事件监听器
vm.$off('test')//移除该事件所有的监听器
vm.off('test',callback)//只移除这个回调函数的监听器
5.3组件或元素引用
5.3.1 ref和vm.$refs
ref是被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的$refs对象上。如果在普通的DOM元素上使用,引用指向的就是DOM元素;
<template>
<div id="app">
<!-- ref和vm.$refs -->
<input type="text" ref="inp"/>
</div>
</template>
<script>
import Vue from 'vue'
export default {
name:"App",
data(){
return{
}
},
methods:{
},
mounted(){
this.$refs.inp.focus();
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
</style>
<template>
<div id="app">
<!-- 监听事件 -->
<course-add v-model="course" @add-course="addCourse"></course-add>
<!-- 组件化 -->
<course-list :courses="courses" @add-course="addCourse"></course-list>
<message ref="msg">新增课程成功!</message>
</div>
</template>
<script>
import Vue from 'vue'
Vue.config.productionTip = false
Vue.component('course-list',{
data(){
return {
selectedCourse:'',
}
},
props:{
courses:{
type:Array,
default:()=>[]
}
},
template:`
<div>
<p v-if="courses.length==0">没有任何课程信息</p>
<ul>
<!-- class绑定 -->
<li v-for="(item,index) in courses" :key=index :class="{active:(selectedCourse===index)}" @click="selectedCourse=index">{{item}}</li>
<!--style绑定 -->
<!--<li v-for="(item,index) in courses" :key=index :style="{backgroundColor:(selectedCourse===index)?'#ddd':'transparent'}" @click="selectedCourse=index">{{item}}</li>-->
</ul>
</div>
`
})
Vue.component('course-add',{
props:['value'],
template:`
<div>
<!--表单输入绑定-->
<input :value="value" @input="onInput" @keydown.enter="addCourse"/>
<!--事件处理-->
<button v-on:click="addCourse">新增课程</button>
</div>
`,
methods:{
addCourse(){
// this.$emit('add-course',this.course);
//this.course =''
this.$emit('add-course')
},
onInput(e){
this.$emit('input',e.target.value)
}
}
})
Vue.component('message',{
props:['show'],
template:`
<div class="message-box" v-if="show">
<strong><slot name="title"></slot></strong>
<slot></slot>
<!--<span class="message-box-close" @click="$emit('update:show',false)">X</span>-->
<span class="message-box-close" @click="toggle">X</span>
</div>
`,
methods:{
toggle(){
this.show =!this.show
}
},
mounted(){
//this.$bus.$on('message-close',()=>{
// this.$emit('update:show',false)
//})
this.$bus.$on('message-close',this.toggle)
}
})
export default {
name:"App",
data(){
return{
//courses:['web全栈','web高级'],
courses:[],
course:"",
selectedCourse:'',//选中项
show:false,
price:0,
showWarn:false,
}
},
methods:{
addCourse(){
this.$refs.msg.toggle()
},
getCourses(){
return new Promise(resolve=>{
setTimeout(()=>{
// resolve(['web全栈','Web高级'])
resolve([{ name: 'web全栈' }, { name: 'web高级' }])
},2000)
})
}
},
async created(){
const courses =await this.getCourses();
this.courses = courses
},
mounted(){
},
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
.message-box{
padding:10px 20px;
background:#4fc08d;
border:1px solid #42b983
}
.success{
background:#4fc08d;
border:1px solid #42b983;
}
.warning{
background:#f66;
border:1px solid #d63200;
}
.message-box-close{
float:right;
}
</style>
注意:
- ref是作为渲染结果被创建的,在初始渲染时不能访问
- $refs不是响应式的,不要试图用它在模板中做数据绑定
- 当v-for作用于元素或者组件时,引用信息将是包含Dom节点或者组件实例的数组