vue总结系列 ------ 插槽

前因

这个是我这个系列的第二篇,我是想以vue官方文档为基础,来进行理解,有人说有官方文档,还要写自己的文章干嘛,我的用意其实是我确实想把官网文档中的案例全部写一遍,来加深自己对这个知识点的理解,因为看还是不如写吧,我在吧我遇到的问题,和我的理解,写出来,以便我以后的忘记,和与我有类似经理的人不用再浪费时间

插槽

其实就是在组件的innerHTML中的内容,他会传递给这个组件中的<slot>元素,其实从功能上来看这个过程有点像prop,但用prop是传递的属性值,而插槽传递的是文本,和HTML,用法就是我们的基本格式不变我变的是其中的一些内容,这样跟好的可控性

组件书写

<navigation-link url="/profile">
  Your Profile
</navigation-link>

模板书写

<a
  v-bind:href="url"
  class="nav-link"
>
  <slot></slot>
</a>

当组件渲染的时候,<slot></slot> 将会被替换为“Your Profile”。插槽内可以包含任何模板代码

包括HTML

<navigation-link url="/profile">
  <!-- 添加一个 Font Awesome 图标 -->
  <span class="fa fa-user"></span>
  Your Profile
</navigation-link>

包括其他组件

<navigation-link url="/profile">
  <!-- 添加一个图标的组件 -->
  <font-awesome-icon name="user"></font-awesome-icon>
  Your Profile
</navigation-link>

如果 <navigation-link> 没有包含一个 <slot> 元素,则该组件起始标签和结束标签之间的任何内容都会被抛弃。

编译的作用域

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

例如:

<navigation-link url="/profile">
  Logged in as {{ user.name }}
</navigation-link>

在官网中这里的意思是user是组件(navigation-link)中的data对象中的值,他不可以直接被外部引用。

后备内容

有时为一个插槽设置具体的后备 (也就是默认的) 内容是很有用的,它只会在没有提供内容的时候被渲染。

例如在一个<submit-button> 组件中他的template是:

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

那么他就可以在下<submit-button> 组件中没提供插槽的时候会有默认的Submit的值,只有在<submit-button> 组件中提供了值才会把默认值给替换掉

具名插槽

这里我们使用2.6版本的语法 v-slot

当我们需要多个插槽的时候,例如对于一个带有如下模板的 <base-layout> 组件他的tenplate为

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

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

修改后

<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 的参数的形式提供其名称:

v-slot最好是写在<template>上面

那我们给组件上添加什么内容呢?

<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>

现在 <template> 元素中的所有内容都将会被传入相应的插槽。任何没有被包裹在带有v-slot 的 <template> 中的内容都会被视为默认插槽的内容

然而,如果你希望更明确一些,仍然可以在一个 <template> 中包裹默认插槽的内容:

<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>

最后渲染的结果为

<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>

注意 v-slot 只能添加在一个 <template> 上 (只有一种例外情况,等下文)

作用域插槽

前面有说插槽(组件中的innerHTML)的值是没办法访问子组件中的数据,但要是我们需要访问,我们要怎么办呢?

官网是这样讲的我来简单的解释一下

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

这里的前题是user是组件current-user中的值不是父组件中的值(这里为全局)

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

组件插槽为:

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

在这里会报错,因为我们上面说过:父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。作用域中没有这个值就会报错

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

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

我的理解是这个<slot>上现在具有了一个看变化的属性他叫user,他的值是current-user组件中的user的值

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

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

经过我写过后的理解就是current-user组件之后有定义一个对象user我们需要把他传对应的插槽,对应的插槽在接收通过name的值来对应相应的值,在这里<template v-slot:default="slotProps">的意思是在这里用v-slot来接收,名字为default(默认值)的传过来的值,并把这个值变命名为slotProps这个对象中的一个属性,所以在slotProps.user.firstName就可以找到user中的firstName了

上面有说v-slot只可以写在<template>上唯一一种情况就是:当被提供的内容只有默认插槽时

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

也就是<slot>上没写name,name默认为default;(但我个人建议还是用<tenplate>);

具名插槽的缩写

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

然而,和其它指令一样,该缩写只在其有参数的时候才可用。这意味着以下语法是无效的:

<!-- 这样会触发一个警告 -->
<current-user #="{ user }">
  {{ user.firstName }}
</current-user>

如果你希望使用缩写的话,你必须始终以明确插槽名取而代之:

<current-user #default="{ user }">
  {{ user.firstName }}
</current-user>

解构插槽prop

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

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

其实根据上面的插槽prop和解构(无声明赋值做一个部分)的理解我而为是把我们写的对象{user} 他等于slot传过来的对象了,那么我们写的对象中的user这个属性值就会等于slot传过来的对象中的user的属性值

其实这里的解构插槽我肯了一段时间也不是很懂?如果大家看了之后有懂的可以教下我

我在这里吧我用到的案例(解构的案例发一下),大家看的会理解跟深

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div id="app">
        <my-component-name>
            <template lang="pug"  v-slot:zqx="{user , zqx}"> //这里的zqx只是名字
                 {{user.zqx}}{{zqx.name}}
            </template>
        </my-component-name>
    </div>
    <script src="node_modules/vue/dist/vue.js"></script>
    <script>
        Vue.component('my-component-name',{
            template:`
                    <div
                    class="nav-link"
                    >
                     //传了2个porp这个也是解构的好处
                    <slot v-bind:user="user" :zqx = 'zqx' name="zqx"></slot>
                    </div>
                     `,
            data() {
                return {
                      url:'#',
                      user:{
                          item: 3,
                          zqx: '帅'
                      },
                      zqx:{
                          eag : 18,
                          name : 'zqx',
                          item: 180
                      }
                }
            },       
        })
        new Vue({
            el:'#app',
            //这样的写法好点,和组件一样的写法,确保每一次返回的值(引用类型)都是不全等的
            //因为每一次都会重新执行一次data(),所以返回值都是新的
            data() {
                return {
                    
                }
            },

        })
    </script>
</body>
</html>

总结:

插槽看到这里我的理解就是对组件的高效利用,因为有些组件逻辑结构相同的时候,就是有一些内容需要换的时候,就可以使用插槽

猜你喜欢

转载自blog.csdn.net/qq_39148344/article/details/88973066