1. provide/inject:两个要组合使用,provide使用的父级组件,inject用在子孙组件,功能相当于React的Context。
因为要使用template属性,所以使用import Vue from 'vue/dist/vue.esm',没用使用import Vue from 'vue';
levelTwo要写在levelOne的前面;
当provide的值是json对象时,无法获取this的值,要写成函数形式才能得到this的值,
通过provide/inject得到的数据不具有reactive的特性,就下面的例子来说,provide提供的值是
{
name:"Jack",
age:18
}
根组件再怎么修改age的值,LevelTwo组件的age值永远是18,不会改变,意思就是说,通过这种方式传递的值是不会放生变化的,但是,可以这样做,比如:data的值{name:"Jack",age:18},data的值其实是json对象的地址,意思就是data的值是一个地址,不能改变,但是可以修改地址中存放数据的内容。
import Vue from 'vue/dist/vue.esm'
const levelTwo={
inject:['name','age'],
template:`
<div>
<div>I am levelTwo</div>
<div>This is the data from root:{{name}},{{age}}</div>
</div>`
}
const levelOne={
name: 'comp',
components:{
levelTwo:levelTwo
},
template:`
<div>
<div>I am levelOne</div>
<levelTwo />
</div>`
}
new Vue({
components:{
levelOne
},
provide:function(){
return{
name:"Jack",
age:this.age
}
},
template:`
<div>
<level-one />
<input type="text" v-model="age" />
<div>根组件age:{{age}}</div>
</div>`,
data:function(){
return {
age: 18
}
}
}).$mount('#app')
将provide/inject方式得到的值具有reactive性能
import Vue from 'vue/dist/vue.esm'
const levelTwo={
inject:['name','data'],
template:`
<div>
<div>I am levelTwo</div>
<div>This is the data from root:{{name}},{{data.age}}</div>
</div>`
}
const levelOne={
name: 'comp',
components:{
levelTwo:levelTwo
},
template:`
<div>
<div>I am levelOne</div>
<levelTwo />
</div>`
}
new Vue({
components:{
levelOne
},
provide:function(){
const data = {}
Object.defineProperty(data, 'age', {
get: () => this.age,
enumerable: true
})
return{
name:"Jack",
data:data
}
},
template:`
<div>
<level-one />
<input type="text" v-model="age" />
<div>根组件age:{{age}}</div>
</div>`,
data:function(){
return {
age: 18
}
}
}).$mount('#app')
2. slot
import Vue from 'vue/dist/vue.esm'
//import App from './App.vue'
Vue.config.productionTip = false;
const levelOne={
name: 'comp',
template:`
<div>
<slot name="header"/>
<div>This is body</div>
<slot name="footer" />
</div>`
}
new Vue({
components:{
levelOne
},
template:`
<div>
<level-one>
<div slot="header">This is slot content: header</div>
<div slot="footer">This is slot content: footer</div>
</level-one>
</div>`,
}).$mount('#app')
在slot中使用变量
可以使用props,在slot标签上的内容的全部props赋值给slot-scope="props111"中的props111变量,习惯将props111写成props。
slot中的变量,是指slot在定义时所在的组件中的变量。如果想使用其它组件的数据,可以通过props的方式。
显示的内容依次是123 abc 18
import Vue from 'vue/dist/vue.esm'
const levelOne={
name: 'comp',
data:function(){
return{
value:'abc'
}
},
template:`
<div>
<slot :value='value' age="18" ></slot>
</div>`
}
new Vue({
components:{
levelOne
},
data:function(){
return{
value:123
}
},
template:`
<div>
<level-one>
<div slot-scope="props111">{{value}} {{props111.value}} {{props111.age}}</div>
</level-one>
</div>`,
}).$mount('#app')
3. render
在了解render属性之前,先了解一下原生事件和自定义事件,原生事件就是原生DOM上绑定的事件,自定义事件就是组件标签上定义的事件,组件标签上的自定义事件,必须由$emit()触发。
import Vue from 'vue/dist/vue.esm'
const levelOne={
name: 'comp',
data:function(){
return{
value:'abc'
}
},
methods:{
handleClick:function(){
this.$emit('myClick')
},
},
template:`
<div v-on:click='handleClick'>
<slot :value='value' age="18" ></slot>
</div>`
}
new Vue({
components:{
levelOne
},
data:function(){
return{
value:123
}
},
methods:{
handleClick:function(){
alert(1)
},
handleClick2:function(){
alert(2)
}
},
template:`
<div>
<level-one v-on:myClick="handleClick2">
<div slot-scope="props111">{{value}} {{props111.value}} {{props111.age}}</div>
</level-one>
<div v-on:click="handleClick">1</div>
</div>`,
}).$mount('#app')
将template转化成render,
有一个nativeOn属性,作用是给组件添加原生事件
import Vue from 'vue/dist/vue.esm'
const levelOne={
name: 'comp',
data:function(){
return{
value:'abc'
}
},
methods:{
handleClick:function(){
this.$emit('myClick')
},
},
// template:`
// <div v-on:click='handleClick'>
// <slot></slot>
// </div>`,
render(createElement) {
return createElement('div',
{
on:{
click:this.handleClick
}
},this.$slots.default)
}
}
new Vue({
components:{
levelOne
},
data:function(){
return{
value:123
}
},
methods:{
handleClick2:function(){
alert(2)
}
},
// template:`
// <div>
// <level-one v-on:myClick="handleClick2">
// <div>{{value}}</div>
// </level-one>
// </div>`,
render(createElement){
return createElement(
'level-one',
{
on:{
myClick:this.handleClick2
}
},
this.value
)
}
}).$mount('#app')
4.自定义组件的v-modle
首先了解v-modle做了什么事情
v-modle将变量和元素的props属性上value绑定在一起,当元素的input事件触发时,执行一个函数,这个函数是内部已经定义好的,接受一个参数,将这个参数赋值给v-model绑定的变量
new Vue({
data:function(){
return{
value:123,
value2:456
}
},
methods:{
handleInput:function(e){
this.value=e.target.value
}
},
template:`
<div>
<input type="text" @input="handleInput" :value="value">
<div>{{value}}</div>
<input type="text" v-model="value2">
<div>{{value2}}</div>
</div>`
}).$mount('#app')
也就是说给一个组件加上v-model时,将变量和组件props属性value的值绑定在一起,当组件触发input事件时,将一个值传递给事件函数的参数,就可以实现双向绑定。
import Vue from 'vue/dist/vue.esm'
Vue.config.productionTip = false;
const myComponent = {
props:['value'],
methods:{
handleInput:function(e){
this.$emit('input',e.target.value)
}
},
template:`
<div>
<input type="text" @input="handleInput" :value="value">
</div>`
}
new Vue({
components:{
myComponent
},
data:function(){
return{
number:123,
}
},
template:`
<div>
<my-component v-model='number' />
<div>{{number}}</div>
</div>`
}).$mount('#app')
v-model默认和组件的input事件和props属性上的value相关,但是可以通过组件的modle属性进行修改
import Vue from 'vue/dist/vue.esm'
Vue.config.productionTip = false;
const myComponent = {
model:{
prop:'num',
event:'myInput'
},
props:['num'],
methods:{
handleInput:function(e){
this.$emit('myInput',e.target.value)
}
},
template:`
<div>
<input type="text" @input="handleInput" :value="num">
</div>`
}
new Vue({
components:{
myComponent
},
data:function(){
return{
number:123,
}
},
template:`
<div>
<my-component v-model='number' />
<div>{{number}}</div>
</div>`
}).$mount('#app')
5.组件的继承
import Vue from 'vue/dist/vue.esm'
Vue.config.productionTip = false;
const myComponent = {
props:{
age:{
required:true
}
},
data(){
return {
num:123
}
},
mounted(){
console.log('myComponent')
},
template:`
<div>
<input type="text" :value="num">
<div>{{name}}</div>
<div>{{age}}</div>
</div>`
}
const vueCom = Vue.extend(myComponent)
new vueCom({
propsData:{
age:18
},
mounted(){
console.log('vueCom')
},
data:function(){
return{
num:456,
name:"Jack"
}
},
}).$mount('#app')
网页页面显示内容:456 Jack 18,
控制台打印结果:myComponent,vueCom
说明data可以覆盖原先有的属性,生命周期不会。
6.组件实例的$parent属性,如果B组件在A组件中使用
const myComponent = {
mounted(){
console.log(this.$parent.$options.name)//Root
},
template:`<div>This is myComponent </div>`
}
new Vue({
name:"Root",
components:{
myComponent
},
template:`<div><my-component/> </div>`
}).$mount('#app')
修改组件的parent,只有new的方式可以
不是通过new的方式定义parent,就不能生效。
const parentComponent = {
name:parent
}
const myComponent = {
parent:parentComponent,
mounted(){
console.log(this.$parent.$options.name)//Root
},
template:`<div>This is myComponent </div>`
}
new Vue({
name:"Root",
components:{
myComponent
},
template:`<div><my-component/> </div>`
}).$mount('#app')
通过new的方式
import Vue from 'vue/dist/vue.esm'
//parentComponent组件必须要用new的方式
const parentComponent = new Vue({
name:'parent',
template:`<div>This is parentComponent </div>`
})
const myComponent = {
parent:parentComponent,
mounted(){
console.log(this.$parent.$options.name)//Root
},
template:`<div>This is myComponent </div>`
}
new Vue({
parent:parentComponent,
components: {
myComponent
},
name:"Root",
mounted(){
console.log(this.$parent.$options.name)//parent
},
template:`<div><my-component/> </div>`
}).$mount('#app')