一、v-model的深入理解
v-model:就是v-on:和v-bind:的简写
<div id="app">
<p>姓名:<input type="text" v-model='name'>{{name}}</p>
<!-- v-model: 其实就是v-on:和v-bind:的简写 -->
<p>年龄:<input type="text" v-model='age'>{{age}}</p>
<hr>
<ul class="list">
<li>{{yf.label}}--{{yf.count}}</li>
<li>{{kz.label}}--{{kz.count}}</li>
</ul>
<b-counter :label='yf.label' :value='yf.count' @input='yf.count=$event'></b-counter>
<b-counter :label='kz.label' v-model='kz.count'></b-counter>
</div>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.js'></script>
<script>
Vue.component('b-counter', {
template: `
<div class="counter">
<div class="label">{{label}}</div>
<div class="btn">
<button @click='myCount--' :disabled='myCount===minCount'>-</button>
<input readonly class="txt" type="text" :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) {
//触发一个自定义事件,事件名称是input,将count的最新值作为事件对象传出去。
//注意:自定义事件名称不能使用大写
this.$emit('input', val)
}
}
})
new Vue({
el: '#app',
data: {
name: '张三',
age: 34,
yf:{
label: '衣服:',
count: 5
},
kz:{
label: '裤子:',
count: 5
},
}
})
</script>
二、sync修饰符
绑定属性时,采用:xx.sync修饰符,可以省略update:xx对应的事件绑定。注意:属性绑定必须是:xx.sync。自定义事件必须是update:xx。
<div id="app">
<div>衣服--{{yf}} 裤子--{{kz}} 鞋子--{{xz}}</div>
<hr>
<!-- 绑定属性时,采用:xx.sync修饰符,可以省略update:xx对应的事件绑定 -->
<!-- 约定1:属性绑定必须是:xx.sync -->
<b-counter :yf.sync='yf' @updata:yf='yf=$event' :kz.sync='kz' @updata:kz='kz=$event' :xz.sync='xz' @updata:xz='xz=$event'></b-counter>
</div>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.js'></script>
<script>
Vue.config.productionTip = false
Vue.component('b-counter',{
template: `
<div>
<div class="counter">
<div class="label">衣服:</div>
<div class="btn">
<button @click='yfCount--'>-</button>
<input readonly class="txt" type="text" :value='yfCount'>
<button @click='yfCount++'>+</button>
</div>
</div>
<div class="counter">
<div class="label">裤子:</div>
<div class="btn">
<button @click='kzCount--'>-</button>
<input readonly class="txt" type="text" :value='kzCount'>
<button @click='kzCount++'>+</button>
</div>
</div>
<div class="counter">
<div class="label">鞋子:</div>
<div class="btn">
<button @click='xzCount--'>-</button>
<input readonly class="txt" type="text" :value='xzCount'>
<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){
/* 约定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
}
})
</script>
三、具名插槽
在template组件中采用v-slot:插槽名称的方式,指定使用哪个插槽。
#是v-slot:的简写
<div id="app">
<b-box>
<!-- 在template组件中采用v-slot:插槽名称的方式,指定使用哪个插槽 -->
<!-- #是v-slot:的简写 -->
<template #house>
<div>有5套房子</div>
</template>
<template v-slot:car>
<div>有3辆汽车</div>
</template>
<template v-slot:money>
<div>有100万存款</div>
</template>
</b-box>
</div>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.js'></script>
<script>
Vue.config.productionTip = false
Vue.component('b-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='money'></slot>
</div>
</div>
`
})
new Vue({
el: '#app',
})
</script>
四、作用域插槽
作用域插槽必须是具名插槽,在作用域插槽上,可以通过v-bind:绑定属性,绑定的属性,通过指定的作用域变量去接收。
<div id="app">
<!-- 作用域插槽必须是具名插槽,在作用域插槽上,可以通过v-bind:绑定属性,绑定的属性,通过指定的作用域变量去接收。 -->
<b-box>
<template #list='scope'>
<button @click='scope.list.splice(scope.index,1)'>删除</button>
<button @click='priceUp(scope.list,scope.index)'>加价</button>
<button @click='priceDown(scope.list,scope.index)'>降价</button>
</template>
</b-box>
</div>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.js'></script>
<script>
Vue.component('b-box', {
template: `
<div>
<ul>
<li v-for='(item,index) in list' :key='index'>
<span>{{item.id}}--{{item.name}}--{{item.price}}</span>
<slot name='list' v-bind:index='index' v-bind:list='list'></slot>
</li>
</ul>
</div>
`,
data() {
return {
list: [
{
id: 1001,
name: '小米手机',
price: 2999
},
{
id: 1002,
name: '华为手机',
price: 4999
},
{
id: 1003,
name: '苹果手机',
price: 6999
},
{
id: 1004,
name: '红米手机',
price: 1999
},
]
}
}
})
new Vue({
el: '#app',
methods: {
priceUp(list,index){
list[index].price+=1000
},
priceDown(list,index){
list[index].price-=1000
}
},
})
</script>
五、混入
使用Vue.mixin()给所有的Vue实例混入统一的成员。里面可以写数据,计算属性,方法,监听器。
在Vue自己实例中写的数据不能在所有成员中使用,只能自己调用。
<div id="app1">
<p>姓名:<input type="text" v-model='name'></p>
<p>年龄:<input type="text" v-model='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>
<p><button @click='jieshao'>介绍</button></p>
<div>汽车信息:{{car}}</div>
<button @click='getSubjects'>请求课程信息</button>
<div>
{{subjects}}
</div>
</div>
<hr>
<div id="app2">
<p>姓名:<input type="text" v-model='name'></p>
<p>年龄:<input type="text" v-model='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>
<p><button @click='jieshao'>介绍</button></p>
<div>飞机信息:{{plane}}</div>
</div>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.js'></script>
<script src='https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.js'></script>
<script>
Vue.config.productionTip = false
/* 给所有的vue实例混入统一的成员 */
Vue.mixin({
data() {
return {
name: '',
age: 0,
sex: '男',
salary: 1000
}
},
computed: {
salary2() {
return this.salary * 0.8
}
},
methods: {
jieshao() {
alert(`大家好!我叫${this.name},性别是${this.sex},今天是${this.age}岁了。`)
},
//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',
/* 注意:先执行混入的生命周期,再执行自己的生命周期 */
mounted() {
console.log('app1,组件挂载完成。');
},
data(){
return{
car:{
name:'企鹅汽车',
price:300
},
//课程信息
subjects:[]
}
},
methods: {
async getSubjects(){
let {data} = await this.$get('http://www.bingjs.com:81/Subject/GetSubjectsConditionPages')
this.subjects = data
}
},
})
new Vue({
el: '#app2',
mounted() {
console.log('app2,组件挂载完成。');
},
data(){
return{
plane:{
name:'猪猪飞机',
price:1000
}
}
}
})
</script>