一、语法糖
v-model其实就是v-bind和v-on的语法糖(简写)
在自定义组件中,把绑定数据的属性改成value,监听事件的名称改成input,也可以使用v-model的简写实现双向绑定。否则不能使用。
写法:
Vue.component('b-input', {
template: `
<div class="counter">
<div class="label">{{label}}</div>
<div class="btns">
<button @click="myCount--" :disabled="myCount===minCount">-</button>
<input class="text" type="text" readonly :value="myCount">
<button @click="myCount++" :disabled="myCount===maxCount">+</button>
</div>
</div>
`,
// props选项。用于定义组件的属性。有两种方式:1、定义数组。2、定义对象。props是只读不改
// props: ['label', 'count']
props: {
// 文本
label: {
type: String,
// 允许为空
required: false
},
// 数量
value: {
type: Number,
// 非空
required: true
},
// 最大值
maxCount: {
type: Number,
default: 999
},
// 最小值
minCount: {
type: Number,
default: 1
}
},
// 定义数据
data() {
return {
// 将props接收到的value给myCount
myCount: this.value,
}
},
watch: {
myCount(val) {
// 触发一个自定义事件。事件名称是syncCount。将count的最新值作为事件对象传出去。
// 自定义事件名称不能有大写。
this.$emit('input', val)
}
}
})
let vm = new Vue({
el: "#app",
data: {
name: "李易峰",
age: 34,
// 衣服
yf:
{
label: '衣服',
count: 5
},
// 裤子
kz: {
label: '裤子',
count: 5
}
},
methods: {
updateName(e) {
this.name = e.target.value
}
},
})
页面中使用:
<b-input :label='yf.label' :value="yf.count" @input="yf.count=$event">
</b-input>
<b-input :label='kz.label' v-model="kz.count">
</b-input>
二、.sync修饰符
绑定属性时(:),采用xx.sync修饰符,可以省略@update.xx对应的事件绑定
但是要想省略,需要遵循以下两项约定。
(1)、属性绑定必修时xx.sync。
(2)、自定义事件必须是update:xx
如果组件只回传一份数据,用v-model。如果组件回传多份数据,用.sync修饰符
vue写法:
Vue.component('b-counter', {
template: `
<div>
<div class='conter'>
<div class='label'>衣服</div>
<div class='btns'>
<button @click='yfCount--' class='btn'>-</button>
<input type='text' readonly class='txt' :value='yfCount'>
<button @click='yfCount++' class='btn'>+</button>
</div>
</div>
<div class='conter'>
<div class='label'>裤子</div>
<div class='btns'>
<button @click='kzCount--' class='btn'>-</button>
<input type='text' readonly class='txt' :value='kzCount'>
<button @click='kzCount++' class='btn'>+</button>
</div>
</div><div class='conter'>
<div class='label'>鞋子</div>
<div class='btns'>
<button @click='xzCount--' class='btn'>-</button>
<input type='text' readonly class='txt' :value='xzCount'>
<button @click='xzCount++' class='btn'>+</button>
</div>
</div>
</div>
`,
//要想使用props里面定义的属性,要通过data函数转换一下方可使用
props: ['yf', 'kz', 'xz'],
data() {
return {
yfCount: this.yf,
kzCount: this.kz,
xzCount: this.xz,
}
},
//监听事件
watch: {
yfCount(val) {
// 约定2:自定义事件必须是update:xx
this.$emit('update:yf', val)
},
kzCount(val) {
this.$emit('update:kz', val)
},
xzCount(val) {
this.$emit('update:xz', val)
},
}
})
new Vue({
el: "#app",
data: {
// 衣服数量
yf: 5,
// 裤子数量
kz: 5,
// 鞋子数量
xz: 5
}
})
页面中使用:
<b-counter :yf.sync="yf" :kz.sync="kz" @update:kz="kz=$event" :xz.sync="xz"></b-counter>
三、具名插槽
具名插槽:给插槽取名字
<slot name="house"></slot>
在自定义组件中使用template组件,通过v-slot:插槽名。的方式,指定使用哪个插槽。(简写#插槽名)
<b-box>
//第一种方法
<template v-slot:house>
<div>有5套房子</div>
</template>
//简写
<template #house>
<div>有5套房子</div>
</template>
</b-box>
四:作用域插槽
可以在slot标签上绑定属性,这样外面在使用该插槽时,就可以获取到上面绑定的数据。这样的插槽,我们称之为:作用域插槽
作用域插槽:作用域插槽必须是具名插槽。在作用域插槽上可以通过v-bind(:)绑定属性。
Vue.component('b-box', {
// 可以在slot上面绑定属性
template: `
<div class="box">
<ul>
<li v-for="(item,index) in list" :key="index"><span>{{item.id}}--{{item.name}}--{{item.price}}</span>
<slot name="list" :item="item" :list="list" :index="index">
</slot >
</li>
</ul>
</div>
`
,
data() {
return {
list: [
{
id: 1001,
name: '苹果手机',
price: 5666
},
{
id: 1002,
name: '红米手机',
price: 4666
},
{
id: 1003,
name: '华为手机',
price: 4566
},
{
id: 1005,
name: '小米手机',
price: 3666
},
]
}
},
})
new Vue({
el: "#app",
methods: {
priceDown(list,index){
// 通过下标的方式修改价格
list[index].price-=1000
},
priceUp(list,index){
list[index].price+=1000
}
},
})
绑定的属性,通过指定的作用域变量可以通过自己起的名字去接收。
<b-box>
<template #list="scope">
<button @click="scope.list.splice(scope.index,1)">删除</button>
<button @click="priceDown(scope.list,scope.index)">降价</button>
<button @click="priceUp(scope.list,scope.index)">加价</button>
</template>
</b-box>
五、混入
1、定义:全局混入:Vue.mixin({})。必须要限制性
(1)、mixin()方法的参数是配置对象,Vue实例可以配置的东西,它都可以配置。
2、使用环境:
当页面有几个模块都需要使用到统一的成员以及属性的时候,可以采用全局混入给vue实例混入统一的成员。
3、在全局混入的所有内容,后面设置的vue实例都将拥有。
Vue.mixin({
data() {
return {
name: '',
age: 0,
sex: '男',
salary: 1000
}
},
computed: {
salary2() {
return this.salary * 0.8
}
},
methods: {
sayHi() {
alert(`大家好,我叫${this.name},今年${this.age}岁,性别是${this.sex}`)
},
// get请求
async $get(url, params) {
let { data } = await axios.get(url, { params })
return data
},
// post请求
async $post(url,params){
let {data}=await axios.post(url,params)
return data
}
},
watch: {
age(val) {
if (val > 100) {
alert('年龄不能超过100岁')
this.age = 100
}
}
},
mounted() {
console.log('mixin:组件挂载完成');
},
})
new Vue({
el: "#app1",
data() {
return {
plane: {
name: "马航730",
price: '2345678'
},
}
},
})
new Vue({
el: "#app2",
data() {
return {
star: {
name: '李易峰',
age: 34
},
}
},
})
使用:
<div id="app1">
<p>姓名: <input type="text" v-model="name"></p>
<p>年龄: <input type="text" v-model.number="age"><button @click="age++">++</button></p>
<p>性别: <input type="text" v-model="sex"></p>
<p>税前信息:<input type="text" v-model="salary"> 税后薪资: <input type="text" :value="salary2"></p>
<button @click="sayHi">sayHi</button>
<p>{{plane}}</p>
</div>
<hr>
<div id="app2">
<p>姓名: <input type="text" v-model="name"></p>
<p>年龄: <input type="text" v-model.number="age"><button @click="age++">++</button></p>
<p>性别: <input type="text" v-model="sex"></p>
<button @click="sayHi">sayHi</button>
<p>{{star}}</p>
</div>
4、执行的顺序
(1)、在创建vue实例时,会将mixin里面的成员和vue实例自身的成员进行合并。如果有冲突,则采用vue实例上的成员
(2)、先执行混入的生命周期函数,再执行自己的声明周期函数
Vue.mixin({
mounted() {
console.log('mixin:组件挂载完成');
},
})
new Vue({
mounted() {
console.log(' 页面挂载完成');
},
})
//先打印mixin再打印页面挂载完成
六、混入Ajax
vue.mixin({
methods: {
sayHi() {
alert(`大家好,我叫${this.name},今年${this.age}岁,性别是${this.sex}`)
},
// get请求
async $get(url, params) {
let { data } = await axios.get(url, { params })
return data
},
// post请求
async $post(url,params){
let {data}=await axios.post(url,params)
return data
}
},
})
new Vue({
data(){
// 课程数组
subjects:[]
}
})
引用:
<button @click="getSubjects">请求课程数据</button>
<div>
{{subjects}}
</div>