看着官方文档和实例跟着菜鸟的思路一起学习一下吧

1.插槽内容

比如说你有这样一个父组件:

<template>
  <div>
    <navigation-link url="/profile">
      Your Profile
    </navigation-link>
    <br>
    <navigation-link url="/profile">
      <Icon type="ios-checkmark" size="16"/>
      <span>Your Profile</span>
    </navigation-link>
  </div>
</template>
<script>
  import NavigationLink from '@/components/NavigationLink';
  export default {
    components:{
      NavigationLink
    },
    data(){
      return {
      }
    }
  }
</script>

  然后里面的子组件是这样的:注意里面的slot

<template>
  <a :href="url" class="nav-link">
    <slot></slot>
  </a>
</template>
<script>
    export default {
        name: "NavigationLink",
        props: {
          href:{
            type:String,
            default:''
          }
        },
    }
</script>

  最后看渲染在页面上的结构

 

 

 总结:上面的代码可以看出,slot就是把组件NavigationLink起始标签之间的内容显示出来,如果子组件没有包含<slot></slot>元素,NavigationLink起始标签之间的内容将没有任何意义

2.编译作用域

对编译作用域的理解我想不用很多实例解释

官网给出的这段代码足以说明

<navigation-link url="/profile">
  Clicking here will send you to: {{ url }}
  <!--
  这里的 `url` 会是 undefined,因为其 (指该插槽的) 内容是
  _传递给_ <navigation-link> 的而不是
  在 <navigation-link> 组件*内部*定义的。
  -->
</navigation-link>

  总结:父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。

3.后备内容

有时为一个插槽设置具体的后备 (也就是默认的) 内容是很有用的,它只会在没有提供内容的时候被渲染。例如在一个 <submit-button> 组件中

这句话是官网给出的解释,其实简单地理解就是默认值当你在组件里面不写任何东西的时候你希望有个默认内容,当你写了内容的时候会替代默认值

看个具体代码感受一下:

例如在一个 <submit-button> 组件中:

<button type="submit">
  <slot></slot>
</button>

  我们可能希望这个 <button> 内绝大多数情况下都渲染文本“Submit”。为了将“Submit”作为后备内容,我们可以将它放在 <slot> 标签内

于是我们对上面的组件稍加修改

<button type="submit">
  <slot>Submit</slot>
</button>

  

现在当我在一个父级组件中使用 <submit-button> 并且不提供任何插槽内容时:

<submit-button></submit-button>

 后备内容“Submit”将会被渲染:

<button type="submit">
  Submit
</button>

  如果我们这样使用

<submit-button> Save </submit-button>

 则这个提供的内容将会被渲染从而取代后备内容

<button type="submit"> Save </button>

现在应该完全理解了吧,其实就是名字取得唬人

4.具名插槽

简单的理解就是子组件里面有多个插槽,父组件使用的时候通过不同的插槽名字插入对用的插槽中

有时我们需要多个插槽。例如对于一个带有如下模板的 <base-layout> 组件:

<div class="container">
  <header>
    <!-- 我们希望把页头放这里 -->
  </header>
  <main>
    <!-- 我们希望把主要内容放这里 -->
  </main>
  <footer>
    <!-- 我们希望把页脚放这里 -->
  </footer>
</div>

对于这段代码相信大家都不陌生,就是oa系统里面的一个layout页面,正如注释里面说的,希望每个空缺有对应的内容,这个时候具名插槽就派上用场了

对于这样的情况,<slot> 元素有一个特殊的 attribute:name。这个 attribute 可以用来定义额外的插槽:

<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

  一个不带 name 的 <slot> 出口会带有隐含的名字“default”。

在向具名插槽提供内容的时候,我们可以在一个 <template> 元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称:

<base-layout>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>

  <p>A paragraph for the main content.</p>
  <p>And another one.</p>

  <template v-slot:footer>
    <p>Here's some contact info</p>
  </template>
</base-layout>
<base-layout>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>

  <template v-slot:default>
    <p>A paragraph for the main content.</p>
    <p>And another one.</p>
  </template>

  <template v-slot:footer>
    <p>Here's some contact info</p>
  </template>
</base-layout>

  这两个写法是一样的

  现在 <template> 元素中的所有内容都将会被传入相应的插槽。任何没有被包裹在带有 v-slot 的 <template> 中的内容都会被视为默认插槽的内容。  说的就是中间那两个p标签

任何一种写法都会渲染出:

<div class="container">
  <header>
    <h1>Here might be a page title</h1>
  </header>
  <main>
    <p>A paragraph for the main content.</p>
    <p>And another one.</p>
  </main>
  <footer>
    <p>Here's some contact info</p>
  </footer>
</div>

  

5.作用域插槽

有时让插槽内容能够访问子组件中才有的数据是很有用的。 这个官方解释有点绕,简单地理解就是父组想修改插槽里面的东西,需要访问插槽里面的值

例如,设想一个带有如下模板的 <current-user> 子组件:

<span>
  <slot>{{ user.lastName }}</slot>
</span>

  我们可能想换掉备用内容,用名而非姓来显示。如下:

<current-user>
  {{ user.firstName }}
</current-user>

  然而上述代码不会正常工作,因为只有 <current-user> 组件可以访问到 user 而我们提供的内容是在父级渲染的。

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

<span>
  <slot v-bind:user="user">
    {{ user.lastName }}
  </slot>
</span>

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

<current-user>
  <template v-slot:default="slotProps">
    {{ slotProps.user.firstName }}
  </template>
</current-user>

  在这个例子中,我们选择将包含所有插槽 prop 的对象命名为 slotProps,但你也可以使用任意你喜欢的名字

这波操作你就理解父组件要修改插槽属性值,需要子组件v-bind传递,然后父组件用v-slot:插槽名的方式获取,就可以随便修改内容了

5.1独占默认查找的缩写语法

例如这段 

<current-user v-slot:default="slotProps"> {{ slotProps.user.firstName }} </current-user>

和 <current-user v-slot="slotProps"> {{ slotProps.user.firstName }} </current-user>

注意默认插槽的缩写语法不能和具名插槽混用,因为它会导致作用域不明确:

只要出现多个插槽,请始终为所有的插槽使用完整的基于 <template> 的语法

<current-user>
  <template v-slot:default="slotProps">
    {{ slotProps.user.firstName }}
  </template>

  <template v-slot:other="otherSlotProps">
    ...
  </template>
</current-user>

5.2解构插槽prop

之所以能解构是因为内部工作原理是将你的插槽内容包括在一个传入单个参数的函数里: 

function (slotProps) {
  // 插槽内容
}

这些去看源码应该会有

这意味着 v-slot 的值实际上可以是任何能够作为函数定义中的参数的 JavaScript 表达式。所以在支持的环境下 (单文件组件现代浏览器),你也可以使用 ES2015 解构来传入具体的插槽 prop

<current-user v-slot="{ user }">
  {{ user.firstName }}
</current-user>

  注意看对比,结合之前的解构思想你就明白了

重命名功能

<current-user v-slot="{ user: person }">
  {{ person.firstName }}
</current-user>

自定义后备内容

<current-user v-slot="{ user = { firstName: 'Guest' } }">
  {{ user.firstName }}
</current-user>

6.动态插槽名

这没啥好说的了解了具名插槽,这个无非就是插槽名是动态的而已,这个应用还是很广泛的

<base-layout>
  <template v-slot:[dynamicSlotName]>
    ...
  </template>
</base-layout>

7.具名插槽的缩写

 v-on 和 v-bind 一样,v-slot 也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符 #。例如 v-slot:header 可以被重写为 #header

<base-layout>
  <template #header>
    <h1>Here might be a page title</h1>
  </template>

  <p>A paragraph for the main content.</p>
  <p>And another one.</p>

  <template #footer>
    <p>Here's some contact info</p>
  </template>
</base-layout>

  --------------------------------------------------

插槽的学习就告一段落了,具体的还是要自己在实践中使用哟,趁着今天工作空出来的时间理了一下。

每次百度出来的都是一样的东西,你抄我的我抄你的,这篇是自己原创的,希望读者可以点赞鼓励一下子哦!!!!

 

posted on 2020-09-18 16:23  白不了的黑发  阅读(168)  评论(0编辑  收藏  举报