vue 自定义组件(三) .sync、插槽 、混入
自定义组件 v-model的深入使用
<z-counter :label="yf.label" :value="yf.count" @input="yf.count=$event"></z-counter>
<z-counter :label="kz.label" v-model="kz.count"></z-counter>
比如在普通的input
的标签中,我们可以用v-model
来实现数据的双向绑定,在自定义组件中,我们也可以使用v-model
的双向绑定。
首先我们把属性名改成value
,自定义的方法名为input
,这个时候我们的格式很像v-model
的实现原理,这个时候我们就可以缩写成v-model
来实现数据的双向绑定
在多个数据需要传回页面的时候,这个方法不能够使用。
Vue.component("z-counter", {
template:
`
<div class="counter">
<div class="label">{{label}}</div>
<div class="btns">
<button @click="mydata--" :disabled="mydata===mincount">-</button>
<input type="text" v-model="mydata" class="text" readonly>
<button @click="mydata++" :disabled="mydata===maxcount">+</button>
</div>
</div>
`,
// props 是只读的不能修改
//prop 也可以是数组[属性名]
props: {
label: {
type: String,
//允许为空
required: false,
},
value: {
type: Number,
//不可为空
required: true
},
maxcount: {
type: Number,
default: 999
},
mincount: {
type: Number,
default: 1
}
},
data() {
return {
mydata: this.value
}
},
watch: {
mydata(val) {
this.$emit('input', val)
}
},
})
new Vue({
el: '#app',
data() {
return {
yf:{
label:'衣服',
count:3
},
kz:{
label:'裤子',
count:3
}
}
},
methods: {
}
})
.sync
修饰符
这三种方法都可以实现
<div id="app">
<p>{{yf}}</p>
<p>{{kz}}</p>
<p>{{xz}}</p>
<z-counter :yf.sync="yf" :kz.sync="kz" :xz.sync="xz"></z-counter>
<hr>
<z-counter :yf="yf" :kz="kz" :xz="xz" @update:yf="yf=$event" @update:kz="kz=$event" @update:xz="xz=$event"></z-counter>
<hr>
<z-counter :yf.sync="yf" :kz.sync="kz" :xz.sync="xz" @update:yf="yf=$event" @update:kz="kz=$event" @update:xz="xz=$event"></z-counter>
如果在组件中有多个数据需要回传,这个时候我们可以使用.sync
修饰符 ,可以简化我们的调用过程。
我们的自定义回传方法yfcount(val){ this.$emit('update:yf', val) },
加上update:
的时候,我们可以在属性的后面加上.sync
修饰符,这个时候,我们的回传方法可以省略
this.$emit('update:yf', val) update: 后面连接的是父类传过来的值的名称 ,需要保持一致
Vue.component("z-counter", {
//模板
template:`
<div>
<div class="counter">
<div class="label">衣服:</div>
<div class="btns">
<button @click="yfcount--" >-</button>
<input type="text" v-model="yfcount" class="text" readonly>
<button @click="yfcount++" >+</button>
</div>
</div>
<div class="counter">
<div class="label">裤子:</div>
<div class="btns">
<button @click="kzcount--" >-</button>
<input type="text" v-model="kzcount" class="text" readonly>
<button @click="kzcount++" >+</button>
</div>
</div>
<div class="counter">
<div class="label">鞋子:</div>
<div class="btns">
<button @click="xzcount--" >-</button>
<input type="text" v-model="xzcount" class="text" readonly>
<button @click="xzcount++">+</button>
</div>
</div>
</div> `,
//自定义属性
props: ['yf','kz','xz'],
data() {
return {
//将自定义属性值进行重新赋值给新的变量, 因为自定义属性不能够改变默认值
yfcount:this.yf,
kzcount:this.kz,
xzcount:this.xz,
}
},
watch: {
//监听事件,将新值传回给页面
yfcount(val){
this.$emit('update:yf', val)
},
kzcount(val){
this.$emit('update:kz', val)
},
xzcount(val){
this.$emit('update:xz', val)
}
},
})
new Vue({
el: '#app',
data() {
return {
yf:3,
kz:3,
xz:2
}
},
methods: {
}
})
如果触发的事件名称是update:属性名,那么就可以使用..sync修饰符简化调用的过程。
总结:如果组件只回传一份数据,用v-model。如果组件回传多份数据,用.sync修饰符。
具名插槽
当我们的自定义组件中有多个插槽,这个时候我们需要把信息插入到对应的插槽,这个时候我们需要使用到具名插槽。
我们给插槽添加添加一个name
属性,这个就是插槽的名称。
使用方法:
我们在自定义组件中用<template ></template >
把插入的标签放入到里面 用v-slot:插槽名
来插入固定插槽中
v-slot
可以用#
来代替 v-slot必须是在
<template>上使用
slot` 可以直接写在标签上 如
<span slot="first"><span>
<div id="app">
<z-box>
<template v-slot:house>
<p>4套房子</p>
</template>
<template #car>
<p>三辆车</p>
</template>
<template v-slot:monyse>
<p>1000万存款</p>
</template>
</z-box>
</div>
Vue.config.productionTip = false
Vue.component('z-box', {
template:`
<div class="box">
<div class="item">
<h2>房产信息</h2>
<slot name="house"></slot>
</div>
<div class="item">
<h2>车辆信息</h2>
<slot name="car"></slot>
</div>
<div class="item">
<h2>存款信息</h2>
<slot name="monyse"></slot>
</div>
</div>
`,
})
new Vue({
el: '#app'
})
作用域插槽
像可以在slot
标签上绑定属性,这样外面在使用该插槽时,就可以获取到上面绑定的数据。 这样的插槽,我们称之为:作用域插槽。
我们在自定义组件时,我们可以在<slot>
的插槽中绑定属性 绑定的格式是v-bind:
跟普通绑定的属性是相同的,v-bind
可以省略。
在使用时,我们在template
的标签上用 v-slot:插槽名="变量名"
,通常我们的变量名用scope
来当作变量名
<div id="app">
<z-food>
<template v-slot:list="scope">
<button @click="scope.list.splice(scope.index,1)">删除</button>
<button @click="scope.list[scope.index].price+=100">加价</button>
<button @click="scope.list[scope.index].price-=100">降价</button>
</template>
</z-food>
</div>
Vue.config.productionTip = false
Vue.component("z-food", {
template:`
<div>
<ul>
<li v-for="(item, index) in list" :key="index">{{item.id}}--{{item.name}}--{{item.price}}
<slot name="list" v-bind:index="index" v-bind:list="list"></slot>
</li>
</ul>
</div>
`,
data() {
return {
list:[
{
id:1001,
name:'蛋糕',
price:20
},
{
id:1002,
name:'蛋挞',
price:30
},
{
id:1003,
name:'鸡腿',
price:40
},
{
id:1004,
name:'黑巧',
price:50
},
]
}
},
})
new Vue({
el:"#app"
})
混入
全局混入 -- 注意:必须要先执行
mixin()方法的参数是配置对象,Vue实例可以配置的东西,它都可以配置。
比如:数据,方法,生命周期钩子函数,计算属性,侦听器,过滤器,等等...
在mixin()方法中,是先执行的
在全局混入的内容,之后创建的所有Vue实例包括组件实例都将拥有。
在创建Vue实例时,会将mixin里面的成员跟Vue实例自身的成员进行合并,如果冲突了,最终采用Vue实例身上的成员。
特别注意:生命周期钩子不是合并,是叠加执行,是先执行mixin里面的生命周期钩子,再执行Vue实例里面的生命周期钩子。
Vue.mixin({
data() {
return {
name: '',
age: 22,
sex: '男',
salary: 10000
}
},
computed: {
tosalary() {
return this.salary * 0.86
}
},
methods: {
jian() {
this.age++
if (this.age > 100) {
alert('年龄不能超过100');
this.age = 100
}
}
}
})
混入ajax的基本操作
我们可以在Vue.mixin()
可以写个ajax
的封装方法,这样我们在实例中可以直接调用封装过的ajax
Vue.mixin({
methods: {
// get方法
async $get(url,params){
let {data} = await axios.get(this.base_url+url,{params})
return data
},
// post方法
async $post(url,params){
let {data} = await axios.post(this.base_url+url,params)
return data
}
},
})