Vue基础07api盘点
1 数据相关,批量设置商品价格
1.1 Vue.set
向响应工对象中添加一个属性,并确保这个属性民同样是响应式的且触发视图更新
使用方法: Vue.set(target, propertyName/index, value)
批量设置商品价格
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>购物车</title>
</head>
<body>
<div id="app">
<h2>{{title}}</h2>
<course-add v-model="course" @add-course="addCourse"></course-add>
<p><input type="text" v-model.number="price"> <button @click="batchUpdate">批量更新价格</button></p>
<course-list :courses="courses"></course-list>
<p>课程总数:{{this.courses.length}}</p>
</div>
<script src="../js/vue.js"></script>
<script>
// 课程新增组件
Vue.component('course-add', {
props: ['value'],
template: `
<div>
<input :value="value" @input="onInput" @keydown.enter="addCourse">
<button @click="addCourse">新增</button>
</div>
`,
methods: {
addCourse() {
this.$emit('add-course')
},
onInput(e) {
this.$emit('input', e.target.value)
}
},
})
// 课程列表组件
Vue.component('course-list', {
data() {
return {
selectedCourse: ''
}
},
props: {
courses: {
type: Array,
default: []
}
},
template: `
<div>
<div v-if="courses.length < 1">
没有课程
</div>
<div v-if="courses.length > 0">
<div v-for="item in courses" :key="item.name"
@click="selectedCourse = item.name"
:style="{backgroundColor: (selectedCourse == item.name ? '#ddd' : 'transparent')}">
{{ item.name }} - ¥{{ item.price }}
</div>
</div>
</div>
`
})
function getCourses() {
return new Promise(resolve => {
setTimeout(resolve([{name: 'Java开发'}, {name: 'Web开发'}]), 100)
})
}
const app = new Vue({
el: '#app',
data() {
return {
title: '购物车',
courses: [],
course: '',
price: 0
}
},
async created() {
this.courses = await getCourses()
this.batchUpdate()
},
methods: {
addCourse() {
// if (this.course == '' || this.courses.indexOf(this.course) > -1) {
// return
// }
this.courses.push({name: this.course, price: this.price})
this.course = ''
},
batchUpdate() {
this.courses.forEach(e => {
// e.price = this.price // 这样写没有响应式
Vue.set(e, 'price', this.price)
});
}
},
})
</script>
</body>
</html>
1.2 Vue.delete
删除对象的属性,如果对象是响应式的,确保删除能触发更新视图
使用方法 Vue.delete(target, propertyName/index)
1.3 实例方法
vue.$set()
vue.$delete()
2 事件相关,批量清除多个消息窗口
2.1 vm.$on
监听当前实例上的自定义事件。事件可以由vm.$emit触发。回调函数会接收所有传入事件触发函数的额外参数。
说明:
- 事件的监考者和派发者是同一个实例
vm.$on('test', function(msg){
console.log(msg)
})
2.2 vm.$emit
触发当前实例上的事件。附加参数都会传给监听器调用。
vm.$emit('test', 'hi')
2.3 vm.$once
监听一个自定义事件,但是只触发一次,一旦触发之后,监听器就会被移除。
vm.$on('test', function(msg){
console.log(msg)
})
2.4 vm.$off
移除自定义事件监听器
- 如果没有提供参数,则移除所有的事件监听器
- 如果只提供了事件,则移除该事件所有的监听器
- 如果同时提供了事件与回调,则只移除这个回调的监听器
vm.$off()
vm.$off('test')
vm.$off('test', callback)
2.5 典型应用:事件总线
通过在Vue原型上添加一个Vue实例合为事件总线,实现组件间相互通信,而且不受组件间关系影响
这样做可以在任意组件中使用this.$bus访问该组件实例
Vue.property.$bus = new Vue()
批量清除多个消息窗口
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>购物车</title>
<style>
.message-box {
padding: 10px 20px;
}
.success {
background: #4fc08d;
border: 1px solid #42b983;
}
.warning {
background: #f66;
border: 1px solid #d63200;
}
.message-box-close {
float: right;
}
</style>
</head>
<body>
<div id="app">
<message :show.sync="show" class="success">
<template v-slot:title>恭喜</template>
<template>新增成功</template>
</message>
<message :show.sync="showWarn" class="warning">
<template v-slot:title>警告</template>
<template>新增失败</template>
</message>
<h2>{{title}}</h2>
<div class="toolbar"><button @click="$bus.$emit('message-close')">清空消息</button></div>
<course-add v-model="course" @add-course="addCourse"></course-add>
<p><input type="text" v-model.number="price"> <button @click="batchUpdate">批量更新价格</button></p>
<course-list :courses="courses"></course-list>
<p>课程总数:{{this.courses.length}}</p>
</div>
<script src="../js/vue.js"></script>
<script>
Vue.prototype.$bus = new Vue()
// 弹窗组件
Vue.component('message', {
props: ['show'],
template: `
<div v-if="show" class="message-box">
<slot name="title"></slot>
<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)
})
},
})
// 课程新增组件
Vue.component('course-add', {
props: ['value'],
template: `
<div>
<input :value="value" @input="onInput" @keydown.enter="addCourse">
<button @click="addCourse">新增</button>
</div>
`,
methods: {
addCourse() {
this.$emit('add-course')
},
onInput(e) {
this.$emit('input', e.target.value)
}
},
})
// 课程列表组件
Vue.component('course-list', {
data() {
return {
selectedCourse: ''
}
},
props: {
courses: {
type: Array,
default: []
}
},
template: `
<div>
<div v-if="courses.length < 1">
没有课程
</div>
<div v-if="courses.length > 0">
<div v-for="item in courses" :key="item.name"
@click="selectedCourse = item.name"
:style="{backgroundColor: (selectedCourse == item.name ? '#ddd' : 'transparent')}">
{{ item.name }} - ¥{{ item.price }}
</div>
</div>
</div>
`
})
function getCourses() {
return new Promise(resolve => {
setTimeout(resolve([{name: 'Java开发'}, {name: 'Web开发'}]), 100)
})
}
const app = new Vue({
el: '#app',
data() {
return {
title: '购物车',
courses: [],
course: '',
price: 0,
show: false,
showWarn: false
}
},
async created() {
this.courses = await getCourses()
this.batchUpdate()
},
methods: {
addCourse() {
// if (this.course == '' || this.courses.indexOf(this.course) > -1) {
// return
// }
if (this.course) {
this.courses.push({name: this.course, price: this.price})
this.course = ''
this.show = true
} else {
this.showWarn = true
}
},
batchUpdate() {
this.courses.forEach(e => {
// e.price = this.price // 这样写没有响应式
Vue.set(e, 'price', this.price)
});
}
},
})
</script>
</body>
</html>
3 节点引用,改造消息提示组件
3.1 ref和vm.$refs
ref被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的$refs对象上。如果在普通的DOM元素上使用,引用指向的就是DOM元素,如果用在子组件上,引用就指向组件实例
注意:
- ref是作为渲染结果被创建的,在初始渲染时不能访问它们
$refs不是响应式的,不要试图用它在模板中做数据绑定- 当
v-for用于元素或组件时,引用信息将是包含DOM节点或股份制实例的数组
要求:
-
设置输入框焦点
-
改造message组件用打开、关闭方法控制显示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>购物车</title>
<style>
.message-box {
padding: 10px 20px;
}
.success {
background: #4fc08d;
border: 1px solid #42b983;
}
.warning {
background: #f66;
border: 1px solid #d63200;
}
.message-box-close {
float: right;
}
</style>
</head>
<body>
<div id="app">
<message ref="msgSuccess" class="success">
<template v-slot:title>恭喜</template>
<template>新增成功</template>
</message>
<message ref="msgWarning" class="warning">
<template v-slot:title>警告</template>
<template>新增失败</template>
</message>
<h2>{{title}}</h2>
<div class="toolbar"><button @click="$bus.$emit('message-close')">清空消息</button></div>
<course-add v-model="course" @add-course="addCourse"></course-add>
<p><input type="text" v-model.number="price"> <button @click="batchUpdate">批量更新价格</button></p>
<course-list :courses="courses"></course-list>
<p>课程总数:{{this.courses.length}}</p>
</div>
<script src="../js/vue.js"></script>
<script>
Vue.prototype.$bus = new Vue()
// 弹窗组件
Vue.component('message', {
data() {
return {
show: false
}
},
template: `
<div v-if="show" class="message-box">
<slot name="title"></slot>
<slot></slot>
<span class="message-box-close" @click="toggle()">X</span>
</div>
`,
mounted () {
this.$bus.$on('message-close', () => {
this.toggle()
})
},
methods: {
toggle() {
this.show = !this.show
}
},
})
// 课程新增组件
Vue.component('course-add', {
props: ['value'],
template: `
<div>
<input :value="value" ref="inp" @input="onInput" @keydown.enter="addCourse">
<button @click="addCourse">新增</button>
</div>
`,
methods: {
addCourse() {
this.$emit('add-course')
},
onInput(e) {
this.$emit('input', e.target.value)
}
},
mounted () {
this.$refs.inp.focus()
}
})
// 课程列表组件
Vue.component('course-list', {
data() {
return {
selectedCourse: ''
}
},
props: {
courses: {
type: Array,
default: []
}
},
template: `
<div>
<div v-if="courses.length < 1">
没有课程
</div>
<div v-if="courses.length > 0">
<div v-for="item in courses" :key="item.name"
@click="selectedCourse = item.name"
:style="{backgroundColor: (selectedCourse == item.name ? '#ddd' : 'transparent')}">
{{ item.name }} - ¥{{ item.price }}
</div>
</div>
</div>
`
})
function getCourses() {
return new Promise(resolve => {
setTimeout(resolve([{name: 'Java开发'}, {name: 'Web开发'}]), 100)
})
}
const app = new Vue({
el: '#app',
data() {
return {
title: '购物车',
courses: [],
course: '',
price: 0
}
},
async created() {
this.courses = await getCourses()
this.batchUpdate()
},
methods: {
addCourse() {
// if (this.course == '' || this.courses.indexOf(this.course) > -1) {
// return
// }
if (this.course) {
this.courses.push({name: this.course, price: this.price})
this.course = ''
this.$refs.msgSuccess.toggle()
} else {
this.$refs.msgWarning.toggle()
}
},
batchUpdate() {
this.courses.forEach(e => {
// e.price = this.price // 这样写没有响应式
Vue.set(e, 'price', this.price)
});
}
},
})
</script>
</body>
</html>
4 小技巧
vscode小技巧
输入p>input+button后按回车
vue小技巧
<!-- 加一个number修饰符,price会转化成number -->
<input type="text" m-model.number="price">