插槽
slot 是 vue 的内置组件。
简单使用
定义一个布局组件,里面放什么会在调用组件时决定,我们不会在布局组件里进行内容设置。在组件标签内部写的内容,可以通过 slot 在组件内部模板中进行使用。
import Vue from 'vue'
const component = {
template: `
<div :style="style">
<slot></slot>
</div>
`,
data () {
return {
style: {
width: '200px',
height: '200px',
border: '1px solid #aaa'
}
}
}
}
new Vue({
components: {
CompOne: component
},
el: '#root',
data () {
return {
value: '123'
}
},
template: `
<div>
<comp-one v-model="value">
<span>this is content</span>
</comp-one>
</div>
`
})
具名插槽
通过 slot 的 name 属性可以指定插入多个内容。
import Vue from 'vue'
const component = {
template: `
<div :style="style">
<div class="header">
<slot name="header"></slot>
</div>
<div class="body">
<slot name="body"></slot>
</div>
</div>
`,
data () {
return {
style: {
width: '200px',
height: '200px',
border: '1px solid #aaa'
}
}
}
}
new Vue({
components: {
CompOne: component
},
el: '#root',
data () {
return {
value: '123'
}
},
template: `
<div>
<comp-one v-model="value">
<span slot="header">this is content</span>
<span slot="body">this is body</span>
</comp-one>
</div>
`
})
作用域插槽
scoped slot ,作用域插槽,组件内属性通过作用域插槽传出进行使用。
通常,插槽内使用的属性,使用的是引用组件的组件的属性值。
import Vue from 'vue'
const component = {
template: `
<div :style="style">
<slot></slot>
</div>
`,
data () {
return {
style: {
width: '200px',
height: '200px',
border: '1px solid #aaa'
}
}
}
}
new Vue({
components: {
CompOne: component
},
el: '#root',
data () {
return {
value: '123'
}
},
template: `
<div>
<comp-one v-model="value">
<span>{{value}}t</span>
</comp-one>
</div>
`
})
如果希望插槽模板中使用的属性是组件中的属性时,就用到了 scoped slot。
import Vue from 'vue'
const component = {
template: `
<div :style="style">
<slot :value="value" aaa="111"></slot>
</div>
`,
data () {
return {
style: {
width: '200px',
height: '200px',
border: '1px solid #aaa'
},
value: 'component value'
}
}
}
new Vue({
components: {
CompOne: component
},
el: '#root',
data () {
return {
value: '123'
}
},
template: `
<div>
<comp-one v-model="value">
<span slot-scope="props">{{props.value}} {{props.aaa}} {{value}}</span>
</comp-one>
</div>
`
})
给组件加 ref
打印结果 this.$refs.comp
是 vue 组件,this.$refs.span
打印出来的是 html 节点,这也是 ref 用在组件和 html 原生标签上的区别。
可以通过 $refs
得到组件,进而调用组件的变量和方法,如 this.$refs.comp.value
拿到了组件内部变量 value 值。所以可以通过 ref 操纵组件上的内容(推荐用 props 操纵),除非特殊情况。
mounted () {
console.log(this.$refs.comp, this.$refs.span, this.$refs.comp.value)
},
template: `
<div>
<comp-one ref="comp">
<span slot-scope="props" ref="span">{{props.value}} {{props.aaa}} {{value}}</span>
</comp-one>
</div>
`
provide inject越级得实例
$parent
只能到 组件上一级,如果是跨域多级是不行的,通过 provide 和 injection 可以 越级拿到 vue 实例。
import Vue from 'vue'
const ChildComponent = {
template: `<div>child component</div>`,
inject: ['yeye', 'value'], // 通过 inject 注入
mounted () {
console.log(this.yeye, this.value) // 在子子组件打印 爷爷实例和数据
}
}
const component = {
name: 'comp',
components: {
ChildComponent
},
template: `
<div :style="style">
<slot :value="value" aaa="111"></slot>
<child-component />
</div>
`,
data () {
return {
style: {
width: '200px',
height: '200px',
border: '1px solid #aaa'
},
value: 'component value'
}
}
}
new Vue({
components: {
CompOne: component
},
provide () { // 通过 provide,提供 实例 和 实例的一个属性
return {
yeye: this,
value: this.value
}
},
el: '#root',
data () {
return {
value: '123'
}
},
mounted () {
console.log(this.$refs.comp, this.$refs.span, this.$refs.comp.value)
},
template: `
<div>
<comp-one ref="comp">
<span slot-scope="props" ref="span">{{props.value}} {{props.aaa}} {{value}}</span>
</comp-one>
</div>
`
})
默认情况,provide 不提供 reactive 的属性的,所以我们改 value 的值,子孙组件里 Inject拿到的 value 是不会跟着变的。如果需要改变,需要自己给指定的属性提供 get 方法。这样子孙组件拿到的 data.value 都是通过 get 方法,而 get 方法每次都会获取最新的 value。这个方法比较 hack,可能会被废弃。
// 子孙组件
const ChildComponent = {
template: `<div>child component: {{data.value}}</div>`,
inject: ['yeye', 'data'],
mounted () {
console.log(this.yeye, this.value)
}
}
// 爷爷组件
provide () {
const data = {}
Object.defineProperties(data, 'value', {
get: () => this.value,
enumerable: true
})
return {
yeye: this,
value: this.value
}
},