前端学习——插槽

时光总嘲笑我的痴心妄想 提交于 2020-02-20 18:09:42

一 插槽的简单用法

1.1 用处和用法

当自定义组件没有slot元素的时候,则该标签开始至结束之间的全部内容都会被丢弃。
当使用插槽slot的时候,插槽内可以包含任意内容,包括HTML,如:

<div id="app">
    <my_div>
        input:
        <input type="button" value="按钮">
    </my_div>
</div>

在这里插入图片描述

new Vue({
    el: '#app',
    components: {
        my_div: {
            template: `
                <div>
                    <slot></slot>
                </div>
            `
        }
    }
})

1.2 编译作用域

重要:VUE的作用域应该好好整理下
插槽不在标签作用域的范围内,比如这里的{{message}}就没有用,VUE会报错

[Vue warn]: Property or method “message” is not defined on the instance but referenced during render.

<div id="app">
    <my_div message="你好哇,李银河">
        author:{{message}}{{author}}
        <input @click='display_alert' type="button" value="按钮">
    </my_div>
</div>

而定义在VUE实例中的属性则可以使用(和native html一样)
在这里插入图片描述

new Vue({
    el: '#app',
    data: {
        author: "王小波"
    },
    methods:{
        display_alert:function(){
            alert("Dont worry! Be Happy!")
        }
    },
    components: {
        my_div: {
            props: {
                message: {
                    type: String
                }
            },
            template: `
                <div>
                    {{message}}<br>
                    <slot></slot>
                </div>
            `
        }
    }
})

1.3 使用默认内容

对于自定义组件my_button来说,在html中,若不定义插槽,则显示“默认内容”:

    <div id="app">
        <my_button></my_button>
    </div>

在这里插入图片描述
若提供内容,则替换

    <div id="app">
        <my_button>世说新语</my_button>
    </div>

在这里插入图片描述

new Vue({
    el: '#app',
    components: {
        my_button: {
            methods: {
                display_alert: function () {
                    alert("DONT WORRY! BE HAPPY!!")
                }
            },
            template: `
                <button type = "submit" @click='display_alert'>
                    <slot>默认内容</slot>
                </button>
            `
        }
    }
})

二 具名插槽

通过<slot name="xxx"><slot>的方式来定义一个具名插槽
通过<template v-slot:xxx></template>的方式来使用具名插槽,效果如下:
在这里插入图片描述
.html

<div id=app>
    <base_layout>
        <template v-slot:header>
            标题,在组件中定义好了格式
        </template>

        这一部分是段落内容<br>
        不需要使用`template v-slot`来定义<br>

        <template v-slot:contact>
            <a href="mailto:someone@example.com">someone@example.com</a>
        </template>
    </base_layout>
</div>

自定义组件的内容:

<div class="container">
    <header>
        <h1><slot name="header"></slot></h1>
    </header>
    <main>
        <slot></slot>
        <br>
    </main>
    <footer>
        联系方式部分:
        <slot name="contact"></slot>
    </footer>
</div>

三 作用域插槽

1.2中提到插槽的编译作用域提到:插槽内容是不能访问子组件数据的。那要怎么才能用到呢?
作用域插槽需要具名插槽的帮助:

  1. 通过v-solt:插槽名="prop对象集合名"
  2. 用prop对象集合名调用某一个prop
  3. 在模板中通过<slot v-bind:obj="object" :da="date"></slot>绑定将子组件的一个属性和父组件prop绑定

在这里插入图片描述

<div id="app">
    <my_greet date="星期一" object="王小波">
        <template v-slot:default="test">
            {{test.da}}的{{test.obj}}
          </template>
    </my_greet>
</div>
new Vue({
    el: '#app',
    components: {
        my_greet: {
            props: ['date','object'],
            template: `
                <div>
                    你好,
                    <slot v-bind:obj="object" :da="date"></slot>
                </div>
            `
        }
    }
})

3.1 解构插槽Prop(?)

教程
什么是解构?

四 动态插槽名(?)

动态参数一节的教程
疑问:使用dynamicSlotName的时候,使用什么呢?试了直接用dynamicSlotName.xxx会报错?因为可能不怎么用这个功能,所以就先跳过了。

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

五 缩写

5.1 具名插槽的缩写

(v-slot:) 替换为字符 #。例如 v-slot:header 可以被重写为 #header

5.2 默认插槽的缩写

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

缩写为:

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

六 示例

在这里插入图片描述

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title></title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id=app>
        <todo_list v-bind:todos="todos">
            <template #default="props">
                <span v-if="props.todo.isComplete"></span>
                {{ props.todo.text }}
            </template>
        </todo_list>
    </div>

    <script type="text/javascript">

        new Vue({
            el: '#app',
            data:{
                todos:[
                    {id:1, text:"内容一", isComplete:false},
                    {id:2, text:"内容二", isComplete:false},
                    {id:3, text:"内容三", isComplete:true}
                ]
            },
            components: {
                todo_list: {
                    props:['todos'],
                    template: `
                    <ul>
                    <li
                        v-for="todo in todos"
                        v-bind:key="todo.id"
                    >
                    <slot :todo="todo">
                        {{ todo.text }}
                    </slot>
                    </li>
                    </ul>
                    `
                }
            }
        })
    </script>
</body>

</html>

官方文档无法查看效果的问题在于:
文档中应该是v-if="todo.todo.isCompletet"{{todo.todo.text}}

<todo-list v-bind:todos="todos">
  <template v-slot:todo="{ todo }">
    <span v-if="todo.isComplete"></span>
    {{ todo.text }}
  </template>
</todo-list>

#疑问

1. 页面渲染的详细、具体过程

比如这一段话:

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

什么是父级渲染

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!