Evan's blog Evan's blog
首页
关于
  • 分类
  • 标签
  • 归档
  • H5&CSS3
  • JS
  • TS
  • Node
  • Webpack
  • Vue2
  • Vue3
  • 微信小程序
  • Andorid
  • Flutter
推荐
GitHub (opens new window)

conanan

真相只有一个
首页
关于
  • 分类
  • 标签
  • 归档
  • H5&CSS3
  • JS
  • TS
  • Node
  • Webpack
  • Vue2
  • Vue3
  • 微信小程序
  • Andorid
  • Flutter
推荐
GitHub (opens new window)
  • 基础

  • 组件

    • 组件化开发
    • 插槽
      • 基本使用
      • 具名插槽
        • 2.6.0 后语法
        • 2.6.0 前语法
      • 作用域插槽
        • 编译作用域
        • 作用域插槽—2.6.0 后语法
        • 作用域插槽—2.6.0 前语法
        • 示例
  • Vue CLI

  • Vue Router

  • Vue2.x
  • 组件
xugaoyi
2020-12-27
目录

插槽

# 插槽 slot

slot noun

/slɑːt/

a long, narrow hole, especially one for putting coins into or for fitting a separate piece into

为什么使用 slot

类似 USB 插槽,用于扩展,让使用者决定组件显示的内容。抽取共性,留有扩展。不需要通过状态来控制显示与否!类似接口

# 基本使用

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Title</title>
  </head>

  <body>
    <div id="app">
      <my-component>
        <button>666</button>
      </my-component>
      <hr />
      <my-component>
        <a href="#">QQ</a>
      </my-component>
      <hr />
      <my-component> </my-component>
      <hr />
      <my-component>
        <!-- 会把所有内容替换到插槽里 -->
        <button>666</button>
        <a href="#">QQ</a>
      </my-component>
    </div>

    <template id="myComponent">
      <div>
        <h2>组件</h2>
        <!-- 若没有<slot></slot>标签,则这个组件只能显示h2(当然可以自定义h2中的内容,此处不再赘述),
            其他时候想添加一个button,添加一个img都不可以
            但是当有了<slot></slot>标签后,则可以自定义显示的东西。还可以有默认值 -->
        <slot>
          <button>
            默认插槽值
          </button>
        </slot>
        <!-- 自闭合标签也行,但是没有默认值了 -->
        <!-- <slot /> -->
      </div>
    </template>

    <script src="/lib/vue.js"></script>
    <script>
      const vm = new Vue({
        el: '#app',
        data: {
          message: 'Hello',
        },
        methods: {},
        components: {
          MyComponent: {
            template: '#myComponent',
          },
        },
      })
    </script>
  </body>
</html>
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

# 具名插槽

# 2.6.0 后语法

注意 v-slot 只能添加在 <template> 上,除非当被提供的内容只有默认插槽时,组件的标签才可以被当作插槽的模板来使用。这一点和已经废弃的 slot 不同。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Title</title>
  </head>

  <body>
    <div id="app">
      <!-- 正常工作时显示 li -->
      <current-user :user="outerUser"></current-user>

      <!-- 代码不会正常工作,因为只有 <current-user> 组件可以访问到 user(props或data中,一般都会封装在props中) 而我们提供的内容是在父级渲染的。 -->
      <!-- <current-user :user="outerUser">
        {{ user.firstName }}
      </current-user> -->

      <current-user :user="outerUser">
        <!-- 如下三种方式写都可以 -->
        <!-- <template v-slot:default="props"> -->
        <!-- <template v-slot="props"> -->
        <!-- props 名称可以自定义,推荐使用 props,由于子组件传递过来的值一般都在 props 中。user 是在模版中定义的 attribute -->
        <template #default="props">
          {{ props.user.firstName }}
        </template>
      </current-user>
    </div>

    <template id="currentUser">
      <div>
        <!-- :user="user" 中第一个是作为 attribute 可以自定义(在使用时必须为该 attr),第二个为绑定的子组件中的 props 或 data 数据,一般为 props 的数据 -->
        <slot :user="user">{{ user.lastName }}</slot>
      </div>
    </template>

    <script src="/lib/vue.js"></script>
    <script>
      const vm = new Vue({
        el: '#app',
        data: {
          message: 'Hello',
          outerUser: {
            firstName: 'si',
            lastName: 'li',
          },
        },
        methods: {},
        components: {
          CurrentUser: {
            template: '#currentUser',
            props: {
              user: {
                type: Object,
                default() {
                  return {
                    firstName: 'san',
                    lastName: 'zhang',
                  }
                },
                required: true,
              },
            },
          },
        },
      })
    </script>
  </body>
</html>
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

# 2.6.0 前语法

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Title</title>
  </head>

  <body>
    <div id="app">
      <!-- 正常工作时显示 li -->
      <current-user :user="outerUser"></current-user>

      <!-- 代码不会正常工作,因为只有 <current-user> 组件可以访问到 user(props或data中,一般都会封装在props中) 而我们提供的内容是在父级渲染的。 -->
      <!-- <current-user :user="outerUser">
        {{ user.firstName }}
      </current-user> -->

      <current-user :user="outerUser">
        <!-- 如下两种方式写都可以(#name是v-slot的语法糖) -->
        <!-- <template slot="default" slot-scope="props"> -->
        <!-- props 名称可以自定义,推荐使用 props,由于子组件传递过来的值一般都在 props 中。user 是在模版中定义的 attribute -->
        <template slot-scope="props">
          {{ props.user.firstName }}
        </template>
      </current-user>
    </div>

    <template id="currentUser">
      <div>
        <!-- :user="user" 中第一个是作为 attribute 可以自定义(在使用时必须为该 attr),第二个为绑定的子组件中的 props 或 data 数据,一般为 props 的数据 -->
        <slot :user="user">{{ user.lastName }}</slot>
      </div>
    </template>

    <script src="/lib/vue.js"></script>
    <script>
      const vm = new Vue({
        el: '#app',
        data: {
          message: 'Hello',
          outerUser: {
            firstName: 'si',
            lastName: 'li',
          },
        },
        methods: {},
        components: {
          CurrentUser: {
            template: '#currentUser',
            props: {
              user: {
                type: Object,
                default() {
                  return {
                    firstName: 'san',
                    lastName: 'zhang',
                  }
                },
                required: true,
              },
            },
          },
        },
      })
    </script>
  </body>
</html>
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

# 作用域插槽

# 编译作用域

父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Title</title>
  </head>

  <body>
    <div id="app">
      <!-- 凡是在 Vue 实例管理的 el 中的,都是在 Vue 实例中 -->
      <my-component v-show="isShow"> </my-component>
      <hr />
    </div>

    <template id="myComponent">
      <!-- 只有在组件作用域中写的,才算是组件作用域,在组件中 -->
      <div>
        <h2>组件</h2>
        <button v-show="isShow">按钮</button>
      </div>
    </template>

    <script src="/lib/vue.js"></script>
    <script>
      const vm = new Vue({
        el: '#app',
        data: {
          message: 'Hello',
          isShow: true,
        },
        methods: {},
        components: {
          MyComponent: {
            template: '#myComponent',
            data() {
              return {
                isShow: false,
              }
            },
          },
        },
      })
    </script>
  </body>
</html>
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

# 作用域插槽—2.6.0 后语法

让插槽内容能够访问子组件中才有的数据是很有用的,如下例子:

为了让 user 在父级的插槽内容中可用,我们可以将 user 作为slot元素的一个 attribute 绑定上去。

绑定在 <slot> 元素上的 attribute 被称为插槽 prop。现在在父级作用域中,我们可以使用带值的 v-slot 来定义我们提供的插槽 prop 的名字:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Title</title>
  </head>

  <body>
    <div id="app">
      <!-- 正常工作时显示 li -->
      <current-user :user="outerUser"></current-user>

      <!-- 代码不会正常工作,因为只有 <current-user> 组件可以访问到 user(props或data中,一般都会封装在props中) 而我们提供的内容是在父级渲染的。 -->
      <!-- <current-user :user="outerUser">
        {{ user.firstName }}
      </current-user> -->

      <current-user :user="outerUser">
        <!-- 如下三种方式写都可以 -->
        <!-- <template v-slot:default="props"> -->
        <!-- <template v-slot="props"> -->
        <!-- props 名称可以自定义,推荐使用 props,由于子组件传递过来的值一般都在 props 中。user 是在模版中定义的 attribute -->
        <template #default="props">
          {{ props.user.firstName }}
        </template>
      </current-user>
    </div>

    <template id="currentUser">
      <div>
        <!-- :user="user" 中第一个是作为 attribute 可以自定义(在使用时必须为该 attr),第二个为绑定的子组件中的 props 或 data 数据,一般为 props 的数据 -->
        <slot :user="user">{{ user.lastName }}</slot>
      </div>
    </template>

    <script src="/lib/vue.js"></script>
    <script>
      const vm = new Vue({
        el: '#app',
        data: {
          message: 'Hello',
          outerUser: {
            firstName: 'si',
            lastName: 'li',
          },
        },
        methods: {},
        components: {
          CurrentUser: {
            template: '#currentUser',
            props: {
              user: {
                type: Object,
                default() {
                  return {
                    firstName: 'san',
                    lastName: 'zhang',
                  }
                },
                required: true,
              },
            },
          },
        },
      })
    </script>
  </body>
</html>
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

# 作用域插槽—2.6.0 前语法

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Title</title>
  </head>

  <body>
    <div id="app">
      <!-- 正常工作时显示 li -->
      <current-user :user="outerUser"></current-user>

      <!-- 代码不会正常工作,因为只有 <current-user> 组件可以访问到 user(props或data中,一般都会封装在props中) 而我们提供的内容是在父级渲染的。 -->
      <!-- <current-user :user="outerUser">
        {{ user.firstName }}
      </current-user> -->

      <current-user :user="outerUser">
        <!-- 如下两种方式写都可以(#name是v-slot的语法糖) -->
        <!-- <template slot="default" slot-scope="props"> -->
        <!-- props 名称可以自定义,推荐使用 props,由于子组件传递过来的值一般都在 props 中。user 是在模版中定义的 attribute -->
        <template slot-scope="props">
          {{ props.user.firstName }}
        </template>
      </current-user>
    </div>

    <template id="currentUser">
      <div>
        <!-- :user="user" 中第一个是作为 attribute 可以自定义(在使用时必须为该 attr),第二个为绑定的子组件中的 props 或 data 数据,一般为 props 的数据 -->
        <slot :user="user">{{ user.lastName }}</slot>
      </div>
    </template>

    <script src="/lib/vue.js"></script>
    <script>
      const vm = new Vue({
        el: '#app',
        data: {
          message: 'Hello',
          outerUser: {
            firstName: 'si',
            lastName: 'li',
          },
        },
        methods: {},
        components: {
          CurrentUser: {
            template: '#currentUser',
            props: {
              user: {
                type: Object,
                default() {
                  return {
                    firstName: 'san',
                    lastName: 'zhang',
                  }
                },
                required: true,
              },
            },
          },
        },
      })
    </script>
  </body>
</html>
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

# 示例

父组件替换插槽的标签,但是内容由子组件提供。需求如下:

  • 子组件中包括一数组(可以是父组件通过 props 传递的),如 pLanguages: ['Java', 'Python', 'Go', 'JavaScript', 'C']
  • 需要在多个界面进行展示:
    • 某些界面以水平方向展示
    • 某些界面以列表形式展示
    • 某些界面直接展示一个数组
  • 内容在子组件中,希望父组件告诉如何展示
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Title</title>
  </head>

  <body>
    <div id="app">
      <my-component></my-component>
      <my-component :languanges="outerLanguages">
        <!-- <template v-slot:default="props"> -->
        <!-- <template v-slot="props"> -->
        <template #default="props">
          {{props.languanges.join('-')}}
        </template>
      </my-component>
    </div>

    <template id="myComponent">
      <div>
        <slot :languanges="languanges">
          <!-- slot默认值 -->
          <ul>
            <li v-for="lang in languanges">{{lang}}</li>
          </ul>
        </slot>
      </div>
    </template>

    <script src="/lib/vue.js"></script>
    <script>
      const vm = new Vue({
        el: '#app',
        data() {
          return {
            outerLanguages: ['Java', 'Python', 'Go', 'JavaScript', 'C'],
          }
        },
        methods: {},
        components: {
          MyComponent: {
            template: '#myComponent',
            props: {
              languanges: {
                type: Array,
                default() {
                  return ['C', 'C++']
                },
                required: true,
              },
            },
          },
        },
      })
    </script>
  </body>
</html>
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
编辑 (opens new window)
上次更新: 2022/03/23, 17:55:39
组件化开发
入门

← 组件化开发 入门→

最近更新
01
重点
04-12
02
搭建项目
04-04
03
TS补充
03-30
更多文章>
Theme by Vdoing | Copyright © 2019-2022 conanan | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式