Vue.js进阶

自定义指令

参考资料 : Vue之自定义指令

除了默认设置的核心指令( v-model 和 v-show ), Vue 也允许注册自定义指令。

关于指令,我们可以总结下面几点:

  • 指令是写在 HTML 属性地方的.<input v-model='name' type='text' />
  • 指令都是以 v- 开头的.
  • 指令表达式的右边一般也可以跟值 v-if = false

问题:我们需要一个指令,写在某个HTML表单元素上,然后让它在被加载到DOM中时,自动获取焦点.

1
2
3
4
<div id="app">
<p>页面载入时,input 元素自动获取焦点:</p>
<input type="text" v-focus>
</div>

注册一个全局自定义指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 注册一个全局自定义指令 v-focus
// 第一个参数focus是指令名,指令名在声明的时候,不需要加 v-
Vue.directive('focus', {
// 当绑定元素插入到 DOM 中。
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
// 创建根实例
new Vue({
el: '#app'
})

注册一个局部指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 创建根实例
new Vue({
el: '#app',
directives: {
// 注册一个局部的自定义指令 v-focus
focus: {
// 指令的定义
inserted: function (el) {
// 聚焦元素
el.focus()
}
}
}
})

directive

全局:Vue.directive('自定义指令名、不加v-',{ 参数 })

局部:directives:{ 自定义指令名、不加v-:{ 参数} }

参数: 钩子函数

钩子函数

指令定义函数提供了几个钩子函数(可选):

  • bind: 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。
  • inserted: 被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。
  • update: 被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新。
  • componentUpdated: 被绑定元素所在模板完成一次更新周期时调用。
  • unbind: 只调用一次, 指令与元素解绑时调用。
钩子函数的参数

钩子函数的参数有:

  • el: 指令所绑定的元素,可以用来直接操作 DOM 。
  • binding: 一个对象,包含以下属性:
    • name: 指令名,不包括 v- 前缀。
    • value: 指令的绑定值, 例如: v-my-directive="1 + 1", value 的值是 2
    • oldValue: 指令绑定的前一个值,仅在 updatecomponentUpdated 钩子中可用。无论值是否改变都可用。
    • expression: 绑定值的表达式或变量名。 例如 v-my-directive="1 + 1" , expression 的值是 "1 + 1"
    • arg: 传给指令的参数。例如 v-my-directive:foo, arg 的值是 "foo"
    • modifiers: 一个包含修饰符的对象。 例如: v-my-directive.foo.bar, 修饰符对象 modifiers 的值是 { foo: true, bar: true }
  • vnode: Vue 编译生成的虚拟节点。
  • oldVnode: 上一个虚拟节点,仅在 updatecomponentUpdated 钩子中可用。

Vue组件化

WEB中的组件其实就是页面组成的一部分,好比是电脑中的每一个原件(如硬盘、键盘、鼠标),它是一个具有独立的逻辑和功能或页面,同时又能根据规定的接口规则进行相互融合,变成一个完整的应用。

组件

全局组件和局部组件

  • 全局组件

    1. 基本语法: const xxx = Vue.extend({ template:'' }) Vue.component('xxx',xxx)
    2. 语法糖: Vue.component('xxx',{ template: '' })
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    <div id="app">
    <zykj></zykj>
    </div>

    <script>

    //一种方法
    const myCon = Vue.extend({
    template: '<h1>自定义组件!</h1>'
    })
    // 注册
    Vue.component('zykj',myCon);


    //第二种方法
    // 注册
    Vue.component('zykj', {
    template: '<h1>自定义组件!</h1>'
    })
    // 创建根实例
    new Vue({
    el: '#app'
    })
    </script>
  • 局部组件

    1. 基本语法: const xxx = Vue.extend({ template:'' }) components:{ 'xxx' : xxx }

    2. 语法糖:components: { 'xxx': { template: '' } }

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      <div id="app">
      <zykj></zykj>
      </div>

      <script>

      //一种方法
      const zykj = Vue.extend({
      template: '<h1>自定义组件!</h1>'
      })

      // 创建根实例
      new Vue({
      el: '#app',
      components: {
      // <zykj> 将只在父模板可用
      'zykj': zykj,
      // 第二种方法直接创建
      'myCon' : {
      template : `
      <div>
      <h2>Hello myCon</h2>
      </div>
      `
      }
      }
      })
      </script>
模板抽离

由于template模板书写太麻烦,这里提供几种方法

  1. script text/x-template 方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    <div id="app">
    <zykj></zykj>
    </div>

    <!-- 通过设置id 来与 template 绑定 -->
    <script type="text/x-template" id="myCon">
    <div>
    <h1>我是模板里的</h1>
    </div>
    </script>

    <script>
    Vue.component("zykj",{
    //用于绑定 template模板 中的id属性
    template: "#myCon"
    })
    var vm = new Vue({
    el: '#app',
    components:{

    }
    });
    </script>
  2. <template></template>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <div id="app">
    <zykj></zykj>
    </div>

    <!-- 通过设置id 来与 template 绑定 -->
    <template id="myCon">
    <div>
    <h1>我是模板里的</h1>
    </div>
    </template>

    <script>
    Vue.component("zykj",{
    template: "#myCon"
    })
    var vm = new Vue({
    el: '#app',
    components:{

    }
    });
    </script>

父组件和子组件

子组件就是在父组件的components上定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<div id="app">
<my-con2></my-con>
</div>

<script>

//构造一个组件 (子组件)
const myCon1 = Vue.extend({
template:`
<div>
<h1>Hello myCon1!</h1>
</div>
`
})

//父组件
const myCon2 = Vue.extend({
template:`
<div>
<h1>Hello myCon2!</h1>
<my-con1></my-con1>
</div>
`,
components:{
'myCon1':myCon1
}
})

// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
components:{
'myCon2' : myCon2
}
});
</script>

ref和$refs

访问子组件实例或子元素

尽管存在 prop 和事件,有的时候你仍可能需要在 JavaScript 里直接访问一个子组件。为了达到这个目的,你可以通过 ref 这个 attribute 为子组件赋予一个 ID 引用。例如:

1
<base-input ref="usernameInput"></base-input>

现在在你已经定义了这个 ref 的组件里,你可以使用:

1
this.$refs.usernameInput

来访问这个 <base-input> 实例,以便不时之需。比如程序化地从一个父级组件聚焦这个输入框。在刚才那个例子中,该 <base-input> 组件也可以使用一个类似的 ref 提供对内部这个指定元素的访问,例如:

1
<input ref="input">

甚至可以通过其父级组件定义方法:

1
2
3
4
5
6
methods: {
// 用来从父级组件聚焦输入框
focus: function () {
this.$refs.input.focus()
}
}

这样就允许父级组件通过下面的代码聚焦 <base-input> 里的输入框:

1
this.$refs.usernameInput.focus()

refv-for 一起使用的时候,你得到的 ref 将会是一个包含了对应数据源的这些子组件的数组。

$refs 只会在组件渲染完成之后生效,并且它们不是响应式的。这仅作为一个用于直接操作子组件的“逃生舱”——你应该避免在模板或计算属性中访问 $refs

组件数据存放问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<div id="app">
<zykj></zykj>
</div>

<template id="myCon">
<div>
<h1>{{ title }}</h1>
<h1>我是模板里的</h1>
</div>
</template>

<script>
Vue.component("zykj",{
template: "#myCon",
data(){
return{
title:"我是title"
}
}
})

var vm = new Vue({
el: '#app',
components:{

}
});
</script>

为什么返回的 data data(){ return {} } 为什么组件data必须是函数 自己总结一下:组件data是函数避免了数据共用的问题、通过函数中返回对象会重新开辟空间。。。

组件通信

父组件向子组件传值

使用props属性。

props主要用于父组件传递数据给子组件,是你可以在组件上注册一些自定义特性。当一个值传递给一个prop特性的时候,它就变成了那个组件实例的一个属性。这样在子组件就可以使用该该值。请注意:所有的prop都使得期父子prop之间形成了一个单向下行绑定,即父级prop的更新会向下流动到子组件,但是反过来就不行,子组件不能改变父组件的状态。

每次父组件发生更新时,子组件中所有的prop都会被刷新为最新的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<div id="app">
<!-- 通过v-bind绑定自定义的属性 -->
<zykj v-bind:ctitle="title"></zykj>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<template id="myCon">
<div>
// ctitle 的内容就是 v-bind:ctitle绑定的 title
<h1 >{{ ctitle }}</h1>
<h1>我是模板里的</h1>
</div>
</template>

<script>
const zykj = {
template:"#myCon",
//自定义组件中传入的 ctitle 可以给子组件使用
//数组形式
props: ['ctitle']
// props:{ xxx:{} } 对象形式
}

var vm = new Vue({
el: '#app',
data:{
title: "Hello World"
},
components:{
'zykj':zykj
}

});
<script/>
  • prop 验证

    能判断的所有种类(也就是 type 值)有:String, Number, Boolean, Function, Object, Array, Symbol

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    Vue.component('myComponent', {
    props: {
    // 基础类型检测 (null 意思是任何类型都可以)
    propA: Number,
    // 多种类型
    propB: [String, Number],
    // 必传且是字符串
    propC: {
    type: String,
    //必传
    required: true
    },
    // 数字,有默认值
    propD: {
    type: Number,
    // 当不传入v-bind绑定的数据时、显示的默认数据
    default: 100
    },
    // 数组/对象的默认值应当由一个工厂函数返回
    propE: {
    type: Object,
    default: function () {
    return { message: 'hello' }
    }
    },
    // 自定义验证函数
    propF: {
    validator: function (value) {
    //当函数返回 false 时,输出警告
    return value > 10
    }
    }
    }
    })
  • props对象里的 xXXX 绑定属性不支持驼峰命名 需要改成 x-xxx

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    <!-- 需要改成x-xxx -->
    <zykj v-bind:c-title="title"></zykj>

    <template id="myCon">
    <!-- 别忘了一定要加一个根元素 -->
    <div>
    <!-- 这里可以使用驼峰命名 -->
    <h1>{{ cTitle }}</h1>
    <h1>我是模板里的</h1>
    </div>
    </template>

    const zykj = {
    template:"#myCon",
    //自定义组件中传入的 ctitle 可以给子组件使用
    //数组形式
    props: {
    // 1.通过驼峰命名的 xXxx
    cTitle:{
    type: String
    }
    }
    }
子组件向父组件传值

一般情况下、子组件要向父控件传入数据时、就要使用自定义事件

流程:

  • 子组件中通过 $emit 触发事件
  • 父组件中通过 v-on 来监听子组件事件

$emit( eventName, […args] )

  • eventName:这是一个事件名,会绑定一个方法。当组件触发事件后,将调用这个方法。
  • …args:附加参数,会被抛出,由上述绑定的方法接收使用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<div id="app">
<!-- $emit 传入 btncl 自定义事件 绑定方法btnc -->
<zykj @btncl="btnc"></zykj>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<template id="myCon">
<div>
<button v-for="item in items" @click="btnclick(item)">{{ item.name }}</button>
</div>
</template>

<script>

const zykj = {
template:"#myCon",
data(){
return {
items:[
{id:"1",name:"明日方舟"},
{id:"2",name:"碧蓝航线"},
{id:"3",name:"Miku"},
{id:"4",name:"zykj"},
]
}
},
methods:{
//通过对每个button绑定事件
btnclick(item){
//通过 $emit 像父组件传入自定义事件(btncl)数据为 item
this.$emit('btncl',item)
}
}
}


var vm = new Vue({
el: '#app',
data:{
title: "Hello World"
},
components:{
'zykj':zykj
},
methods:{
//这里获取子组件传入 btncl 的 item 数据
btnc(item){
console.log("btnc",item);
}
}

});
父子组件通信(案例)

需求:父组件通过props向子组件传入数据、并且子组件可以修改父组件的数据,

问题:要避免子组件直接修改父组件的数据、可以根据父组件传入的数据给子组件创建一个data或者computed

方法一:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
<body>
<!-- 父组件 -->
<div id="app">
<!-- :numberx 像子组件传入numx @numxchange 接收子组件传入的数据返回一个函数 -->
<cpn :number1='num1' :number2='num2' @num1change="num1Change" @num2change="num2Change"></cpn>

<h2>父组件{{num1}}</h2>
<input type="text" v-model="num1" >
<h2>父组件{{num2}}</h2>
<input type="text" v-model="num2">

</div>

<!-- 子组件 -->
<template id="cpn">
<div>
<h2>{{number1}}</h2>
<h2>{{dnumber1}}</h2>
<!-- 通过绑定value 监听input事件、通过$emit向父组件传入数据 -->
<input type="text" :value="dnumber1" @input="num1input">
<h2>{{number2}}</h2>
<input type="text" :value="dnumber2" @input="num2input">
</div>
</template>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<script>
// 父传子:props
const cpn = {
template: "#cpn",
data() {
return {
// 通过data绑定一个新的值、内容为传入的numberx
dnumber1:this.number1,
dnumber2:this.number2
}
},
props:{
number1:[Number,String],
number2:[Number,String],
},
methods: {
num1input(event){
this.dnumber1 = event.target.value
//向父组件传入一个自定义事件 numxchange 参数为 dnumberx
this.$emit('num1change',this.dnumber1)
},
num2input(event){
this.dnumber2 = event.target.value
this.$emit('num2change',this.dnumber2)
}
},
};
const app = new Vue({
el: "#app",
data() {
return {
num1:1,
num2:2,
}
},
methods: {
num1Change(value){
this.num1=value
},
num2Change(value){
this.num1=value
}
},
components: {
cpn
},
})
</script>
</body>

方法二:watch 侦听属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<body>
<!-- 父组件 -->
<div id="app">

<cpn :number1='num1' :number2='num2' @num1change="num1Change" @num2change="num2Change"></cpn>

<h2>父组件{{num1}}</h2>
<input type="text" v-model="num1" >
<h2>父组件{{num2}}</h2>
<input type="text" v-model="num2">

</div>

<!-- 子组件 -->
<template id="cpn">
<div>
<h2>{{number1}}</h2>
<!-- v-model 绑定dnumberx -->
<input type="text" v-model="dnumber1">
<h2>{{number2}}</h2>
<input type="text" v-model="dnumber2">
</div>
</template>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<script>
// 父传子:props
const cpn = {
template: "#cpn",
data() {
return {
dnumber1:this.number1,
dnumber2:this.number2
}
},
props:{
number1:[Number,String],
number2:[Number,String],
},
watch: {
//当dnumberx内容改变后会触发
dnumber1(newValue){
this.dnumber1 = newValue * 100
this.$emit('num1change',newValue)
},
dnumber2(newValue){
this.dnumber1 = newValue * 100
this.$emit('num2change',newValue)
}
},
};
const app = new Vue({
el: "#app",
data() {
return {
num1:1,
num2:2,
}
},
methods: {
num1Change(value){
this.num1=value
},
num2Change(value){
this.num1=value
}
},
components: {
cpn
},
})
</script>
</body>

组件访问方式

父组件访问子组件
  • $children:查找当前组件的直接子组件,可以遍历全部子组件, 需要注意 $children 并不保证顺序,也不是响应式的。
  • refs: 查找命名子组件、子组件添加ref='xxx'属性、通过 this.$refs.xxx获取
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<!-- 父组件 -->
<div id="app">
<cpn></cpn>
<cpn></cpn>
<!-- 通过ref给子组件命名 -->
<cpn ref="aaa"></cpn>
<button @click="btnClick" >按钮</button>
</div>
<!-- 子组件 -->
<template id="cpn">
<div>
我是子组件
</div>
</template>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
// 父传子:props
const cpn = {
template: "#cpn",
data() {
return {
name:"我是子组件的name"
}
},
methods: {
showMessage(){
console.log("showMessage");
}
},
};
const app = new Vue({
el: "#app",
data() {
return {
message:"hello"
}
},
methods: {
btnClick(){
// 1. $children 是一个数组 通过索引取值
// console.log(this.$children[0].showMessage)
// for (let cpn of this.$children) {
// console.log(cpn.showMessage)
// }
// 2. $refs 默认返回的是一个对象 组件中添加 ref='xxx'、xxx就为对象中的键名
console.log(this.$refs.aaa.name);
}
},
components: {
cpn
},
})
</script>
子组件访问父组件
  • $parent: parent 访问得到的是它最近一级的父组件
  • $root: 访问得到的是根父组件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<body>
<!-- 父组件 -->
<div id="app">
<cpn></cpn>
<cpn></cpn>
<cpn ref="aaa"></cpn>
</div>

<!-- 子组件 -->
<template id="cpn">
<div>
子组件消息:{{message}}
<button @click="btnClick" >子组件按钮</button>
</div>
</template>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<script>
// 父传子:props
const cpn = {
template: "#cpn",
data() {
return {
message:"我是子组件的name"
}
},
methods: {
btnClick(){
console.log("子组件按钮被点击")
// 1.访问父组件$parent
this.message = this.$parent.message
// 2.访问根组件$root
console.log(this.$root)
console.log(this.$root.message)
}
},
};
const app = new Vue({
el: "#app",
data() {
return {
message:"我是父组件消息"
}
},
methods: {

},
components: {
cpn
},
})
</script>
</body>

插槽

基本使用

插槽(Slot)是Vue提出来的一个概念,正如名字一样,插槽用于决定将所携带的内容,插入到指定的某个位置,从而使模板分块,具有模块化的特质和更大的重用性。

  • 使用<slot></slot>加了个slot标签,在父组件中,可以在父组件内写标签替换子组件标签中的slot
  • 插槽可以使用默认值,slot里的<button>button</button>就是插槽的默认值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<!-- 父组件 -->
<div id="app">
<!-- 不写内容会显示 slot 里的默认内容 -->
<cpn></cpn>
<cpn>
<!-- 子组件里面写的内容会替换 slot 里的内容 -->
<span style="color:red;">这是插槽内容222</span>
</cpn>
<cpn>
<i style="color:red;">这是插槽内容333</i>
</cpn>
<cpn></cpn>
</div>

<!-- 插槽的基本使用<slot></slot> -->
<!-- 子组件 -->
<template id="cpn">
<div>
<div>
{{message}}
</div>
<!-- <button>button</button>为插槽默认值 -->
<slot><button>button</button></slot>
</div>
</template>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<script>
const cpn = {
template: "#cpn",
data() {
return {
message: "我是子组件"
}
},
}

const app = new Vue({
el: "#app",
data() {
return {
message: "我是父组件消息"
}
},
components: {
cpn
},
})
</script>
具名插槽

具名插槽,就是可以让插槽按指定的顺序填充,而没有具名的插槽是按照你填充的顺序排列的,而具名插槽可以自定义排列。

当有多个slot的时候、在子组件里面写上标签会将说有的slot替换

  • 通过<slot name="xxx"></slot> 给插槽取名字
  • 需要添加的标签的添加 slot="xxx" xxx为name的xxx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<!-- 父组件 -->
<div id="app">
<cpn>
<span>没具名</span>
<!-- slot中的left为 子组件中slot中的name -->
<span slot="left">这是左边具名插槽</span>
<!-- 新语法 渲染结果就是 这是中间具名插槽 没有标签包裹 -->
<template v-slot:center>这是中间具名插槽</template>
<!-- 新语法缩写 https://cn.vuejs.org/v2/guide/components-slots.html#具名插槽的缩写 -->
<template #right>这是右边具名插槽</template>
</cpn>
</div>

<!-- 插槽的基本使用使用<slot></slot> -->
<!-- 子组件 -->
<template id="cpn">
<div>
<slot name="left">左边</slot>
<slot name="center">中间</slot>
<slot name="right">右边</slot>
<slot>没有具名的插槽</slot>
</div>
</template>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<script>
const cpn = {
template: "#cpn",
data() {
return {
message: "我是子组件"
}
},
}
const app = new Vue({
el: "#app",
data() {
return {
message: "我是父组件消息"
}
},
components: {
cpn
},
})
</script>
编译作用域

组件都有自己的作用域,自己组件的作用在自己组件内

  • 在父组件中的子组件标签上使用的父组件的、子组件使用的子组件的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<!-- 父组件 -->
<div id="app">
<!-- 使用的vue实例作用域的isShow -->
<cpn v-show="isShow"></cpn>
</div>

<!-- 插槽的基本使用使用<slot></slot> -->
<!-- 子组件 -->
<template id="cpn">
<div>
<h2>我是子组件</h2>
<p>哈哈哈</p>
<!-- 组件作用域,使用的子组件的作用域 -->
<button v-show="isShow"></button>
</div>
</template>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<script>
const cpn = {
template: "#cpn",
data() {
return {
isShwo:false
}
},
}
const app = new Vue({
el: "#app",
data() {
return {
message: "我是父组件消息",
isShow:true
}
},
components: {
cpn
},
})
</script>
作用域插槽

父组件在用子组件来填充插槽的时候 有时候需要用到子组件里面插槽的数据 .
子组件文件插槽上带的数据 在父组件的子组件标签里 让一个标签 带有 slot-scope="xxx" 去接收

步骤:

  • 在子组件模板中的插槽slot 绑定子组件中data中的数据命名为xxx1
  • 父组件中的子组件里通过<template></template> 的属性 slot-scope="xxx2" 接收数据、通过 xxx2.xxx1 获取数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<div id="app">
<zykj>
<!-- 2.5以下必须使用template -->
<template slot-scope="slot">
<!-- <span v-for="item in slot.data">{{item}} - </span> -->
<span>{{ slot.data.join(" - ") }}</span>
</template>
</zykj>

<zykj></zykj>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<template id="myCon">
<div>
<slot :data="pLanguage">
<ul>
<li v-for="item in pLanguage">{{item}}</li>
</ul>
</slot>
</div>
</template>

<script>
const zykj = {
template: "#myCon",
data() {
return {
pLanguage: ['JavaScript','Python','Java']
}
}
}

var vm = new Vue({
el: '#app',
data: {
title: "Hello World"
},
components: {
'zykj': zykj
},
methods: {

}

});
</script>