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')