Vue中slot-scope的深入理解(适合初学者)

时间:2023-01-04 00:41:20

百度上已经有很多的关于slot-scope的文章,但我感觉都是那些以前没学好,又回头学的人,他们都使用了.Vue文件,我觉得有点不适合初学者,所以我就写一篇适合初学者的。

先抛例程:

?
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>组件之通过插槽(slot)分发内容</title>
    <script src="你的vue地址,请下载最新版的"></script>
    <script>
        Vue.component("test-slot",{
           // 插槽允许有默认内容
           template:
               `<div>
                    <strong>Error!</strong>
                    <slot></slot>
                </div>
               `,
            data:function () {
                return {
                    name:"perry"
                }
            }
        });
    //    具名插槽
        Vue.component("slot-name",{
           template:
               `<div>
                      <header>
                            <slot name="header"></slot>
                      </header>
                     <main>
                        <slot ></slot>
                     </main>
                     <footer>
                        <slot name="footer"></slot>
                     </footer>
 
                </div>
               `
        });
        
    //    作用域插槽
        Vue.component("todo-list",{
            inheritAttrs:false,
            props:{
                todos:[Array,Object]
            },
            template:
            `<ul>
                <li v-for="todo in todos" :key="todo.id" style="display: block;" >
                    <slot :data="todo">{{todo.text}}</slot>
                </li>
             </ul>
            `
        });
                
    </script>
    
    <style>
        li{
            list-style: none;
            display: inline-block;
            font-size: 25px;
        }
    </style>
</head>
<body>
    <div id="app">
        <!--1、插槽内容  slot可以接收任何内容、代码,包括组件-->
        <test-slot>Something bad happened.你是谁啊,我认识你吗</test-slot>
        <test-slot>
            Something bad happened.
            <!--允许使用变量,但该变量必须是本作用域的才会生效,这里name的值将会是"岔道口"-->
            <h3>标题{{name}}</h3>
            <img src="img/flower.jfif" alt="图片无法显示">
        
        </test-slot>
        <!--2、具名插槽 slo有一个特殊的属性name,可以使插槽具名-->
        <slot-name>
            <h3>劝学</h3>
            <p>少壮不努力,老大徒伤悲</p>
            <p>光阴似箭,日月如梭</p>
            <template slot="header">
                <ul >
                    <li>主页</li>
                    <li>关于时间</li>
                    <li>关于人生</li>
                    <li>关于未来</li>
                </ul>
            </template>
            <p>你好啊</p>
            <p slot="footer">
                <p>结尾</p>
                <p>粤ICP备6545646456415</p>
            </p>
        </slot-name>
        
        <!--使用作用域插槽,通过slot-scope实现-->
        <todo-list :todos="todos">
            <template slot-scope="slotProps">
                <span v-if="slotProps.data.isTrue">√</span>
                {{slotProps.data.text}}
            </template>
        </todo-list>
        
        <!--使用ES2015结构语法-->
        <todo-list :todos="todos">
            <template slot-scope="{data}">
                <span v-if="data.isTrue">√</span>
                {{data.text}}
            </template>
        </todo-list>       
    </div>
        
    <script>
        new Vue({
            el:"#app",
            data:{
                name:"岔道口",
                todos:[
                    {text:"A",id:1,isTrue:true},
                    {text:"B",id:2,isTrue:true},
                    {text:"C",id:3,isTrue:false},
                    {text:"D",id:4,isTrue:true},
                ],
                // slotProps:""
            }
        })
        
    </script>
</body>
</html>

例程中也写了普通插槽和具名插槽,这个我就不说,我就说一下作用域插槽。首先从“作用域插槽“”这个名字说起,本来你父组件的模板是无法使用到子组件模板中的数据,官网中有一句特别强调的话:父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译。这句话其实挺难理解,举个例子就知道了,

?
1
2
3
4
5
6
7
8
9
10
11
<test-slot>
 
          Something bad happened.
 
         <!--允许使用变量,但该变量必须是本作用域的才会生效,这里name的值将会是"岔道口"-->
 
           <h3>标题{{name}}</h3>
 
           <img src="img/flower.jfif" alt="图片无法显示">
 
</test-slot>

这是我上面的例子,也就是说这里name必须是当前组件里的,不能是test-slot这个组件内部的数据,这是它作用域限制,name这个数据属于父组件的作用域,所以只能是父组件的数据。但是slot-scope的出现却实现了父组件调用子组件内部的数据,子组件的数据通过slot-scope属性传递到了父组件

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//    作用域插槽
    Vue.component("todo-list",{
        inheritAttrs:false,
        props:{
            todos:[Array,Object]
        },
        template:
        `<ul>
            <li v-for="todo in todos" :key="todo.id" style="display: block;" >
                  //这里的:data=“todo”就是讲子组件todo这个数据传给了父组件
                <slot :data="todo">{{todo.text}}</slot>//todo.text是默认值,父组件会把它覆盖掉
            </li>
         </ul>
        `
    });
?
1
2
3
4
5
6
7
<!--使用作用域插槽,通过slot-scope实现-->
<todo-list :todos="todos">
    <template slot-scope="slotProps">
        <span v-if="slotProps.data.isTrue">√</span>
        {{slotProps.data.text}}
    </template>
</todo-list>

使用的时候就是这样,从子组件传过来的名为data值为todo的数据将会被slot-scope接收,需要注意的是,slot-scope接收的是一个对象,这里命名为slotProps,也就是说你传过来的data将会作为slotProps的一个属性,所以需要slotProps.data才能调用到data。前面说了,data的值为todo,todo是什么呢?todo是todos遍历出来的,所以是一个对象。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
new Vue({
    el:"#app",
    data:{
        name:"岔道口",
        todos:[
            {text:"A",id:1,isTrue:true},
            {text:"B",id:2,isTrue:true},
            {text:"C",id:3,isTrue:false},
            {text:"D",id:4,isTrue:true},
        ],
        // slotProps:""
    }
});

我们已经理解了slot-scope特性,那么他有什么运用场景呢?我们可以试想一下,别人写好了一个组件,该组件已经封装好了,但他觉得,数据的显示风格让用户自己定义,就像我们上面,我们希望列表的样式由用户定义,比如我就加了一个√号。一开始最初的数据是我们传进去的,但数据必须进过子组件处理后,写组件那个人肯定希望显示的是处理后的数据。这时候slot-scope就无比重要了。

总结

到此这篇关于Vue中slot-scope深入理解的文章就介绍到这了,更多相关Vue slot-scope理解内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/huangyilinnuli/article/details/81239077