02_Vue 组件化

vue 组件

组件的出现,就是为了拆分Vue实例的代码量的,能够让我们以不同的组件,来划分不能的功能模块,将来需要什么样的功能,就可以去调用。

组件和模块化的不同:

​ 模块化:是从代码逻辑的角度进行划分的,方便代码分层开发,保证每个功能模块职能单一

​ 组件化:是从UI界面的角度进行划分的,前端的组件化,方便UI组件的重用

一、全局组件定义的方式

使用Vue.extend

Vue.extend 属于 Vue 的全局 API,在实际业务开发中我们很少使用,因为相比常用的 Vue.component 写法使用 extend 步骤要更加繁琐一些.

<div id="root">
    <!--组件的使用:以html标签的形式,组件名称作为html的标签名称-->
    <login></login>
</div>

<script src="./js/vue.js" type="text/javascript"></script>
<script type="text/javascript">
    // 方法1:使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。
    // 创建构造器
    var login = Vue.extend({
        //定义组件的模版
        template: "<h1>欢迎使用登录模块</h1>"
    })
    // 需要通过 new login().$mount('#mount-point') 来挂载到指定的元素上。
	// new login().$mount('#root')
    
    // 或者结合 Vue.component('login', login) 来挂载到指定的元素上。
    Vue.component('login', login)
    var vm = new Vue({
    	el: "#root"
    })
</script>

使用Vue.component

<div id="root">
    <!--组件的使用:以html标签的形式,组件名称作为html的标签名称-->
    <register></register>
</div>

<script src="./js/vue.js" type="text/javascript"></script>
<script type="text/javascript">
    // 方法2:直接使用Vue.component方法
    /*
       注意,使用Vue.component 定义全局组件的时候,组件名称使用了驼峰命名,则在引用
       组件的时候,需要把大写的驼峰改为小写字母,同时两个单词之间使用“-”进行连接,
       如果没有小驼峰命名,直接使用即可
    */
    Vue.component("register", {
        // 注意组件里只能有一个根元素,下面的方式是错误的
        // template:"<h1>欢迎新用户注册</h1><h3>注册第一步</h3>"
        // 可以使用一个div将所有元素包括住
        template: "<div><h1>欢迎新用户注册</h1><h3>注册第一步</h3></div>"
    })
    var vm = new Vue({
        el: "#root"
    })
</script>

使用template标签

<div id="root">
    <main-nav></main-nav>
</div>
<!-- 在被控制的app标签外面,使用tempalte元素,定义组件的HTML模板结构 -->
<template id="nav_tpl">
    <!--
		组件模板的html内容仅能有一个根标签,因为组件只会渲染第一个标签
		推荐:template内部定义一个div,然后所有的内容都定义在div里面
	-->
    <div>
        <ul>
            <li><a href="#">首页</a></li>
            <li><a href="#">新闻</a></li>
            <li><a href="#">产品</a></li>
        </ul>
    </div>
</template>

<script type="text/javascript">
    // 方法3,在被控制的#root外部定义组件结构,这种方式有代码高亮
    // 组件命名同样需要注意小驼峰命名的问题
    Vue.component("main-nav", {
        template: "#nav_tpl"
    })
    var vm = new Vue({
        el: "#root"
    })
</script>

二、定义局部组件

<div id="root">
    <page-header></page-header>
    <page-footer></page-footer>
</div>

<script src="./js/vue.js" type="text/javascript"></script>
<script type="text/javascript">
    // 方法3,在被控制的#root外部定义组件结构,这种方式有代码高亮
    // 组件命名同样需要注意小驼峰命名的问题
    var vm = new Vue({
        el: "#root",
        components: {
            pageHeader: {
                template: '<h2>我是网页头部内容</h2>'
            },
            pageFooter: {
                template: '<h2>&copy;版权所有</h2>'
            }
        }
    })
</script>

组件命名规则:

  • 不能和html标签名冲突;

  • 名称多单词;

    • 中划线间隔:my-main,list-nav等
    • 驼峰:myMain,listNav等,定义组件时使用驼峰,使用组件的时候需要把大写的驼峰改为小写字母,同时两个单词之间使用“-”进行连接,因为html标签不区分大小写。

三、全局组件和局部组件使用区别

全局组件注册以后,在不同的Vue实例挂载点内都可以使用,而局部的只能在注册的Vue实例对应的挂载点里使用

四、组件中的data

  • 组件可以有自己的data数据
  • 组件的data和实例的data有点不一样,实例中的data可以为一个对象,也可以是一个方法,但是组件的data必须是一个方法
  • 组件中的data除了必须为一个方法以外,这个方法内部,还必须返回一个对象才行
  • 组件中的data数据使用方式和实例中的data使用方式完全一样
<div id="root">
    <main-nav></main-nav>
</div>
<template id="nav_tpl">
    <div>
        <nav>{{user}}的个人主页</nav>
        <ul>
            <li>姓名:{{user}}</li>
            <li>年龄:{{age}}</li>
            <li>地址:{{address}}</li>
        </ul>
    </div>
</template>
<script src="./js/vue.js" type="text/javascript"></script>
<script type="text/javascript">
    /*
		组件可以有自己的data数据
		组件的data和实例的data有点不一样,实例中的data可以为一个对象,但是组件的data必须是一个方法
		组件中的data除了必须为一个方法以外,这个方法内部,还必须返回一个对象才行
		组件中的data数据使用方式和实例中的data使用方式完全一样
		*/
    Vue.component("main-nav", {
        template: "#nav_tpl",
        // data:{
        // 	user:"张三"
        // }
        /*
        *好处:
        * 1、数据可拥有自己的过程代码(对组件的data数据进行初步处理)
        * 2、组件的数据是在每个组件实例中独有的(隔离的)
        * 3、Vue对象也是一个组件,把它称为父组件,自己定义的组件成为子组件
        * 父组件与子组件之间数据也是隔离的
        */
        data() {
            return {
                user: "张三",
                age: 12,
                address: "河南省郑州市"
            }
        }
    })
    var vm = new Vue({
        el: "#root",
    	data: {
        	message: 'hello vuejs'
        }
    })
</script>

【练习】创建一个可以点击的按钮,每次点击按钮,按钮后边的 数字都会加1,使用组件实现:

<div id="root">
    <!--组件实例1-->
    <data-test></data-test>
    <!--组件实例2-->
    <data-test></data-test>
</div>
<template id="test">
    <div>
        <button @click="add()">递增按钮</button><span>{{count}}</span>
    </div>
</template>

<script src="./js/vue.js" type="text/javascript"></script>
<script type="text/javascript">
    Vue.component("data-test", {
        template: "#test",
        data: function () {
            return {
                count: 1
            }
        },
        methods: {
            add() {
                this.count++;
            }
        }
    })
    var vm = new Vue({
        el: "#root"
    })
</script>

五、切换组件

有如下登录和注册的模板,我们来学习使用3种方式进行切换:

<div id="root">
    <a href="">登录</a>
    <a href="">注册</a>
    <login></login>
    <register></register>
</div>

<template id="login">
    <div>
        <h2>用户登录</h2>
        <p>用户名:<input type="text"></p>
        <p>密码:<input type="text"></p>
    </div>
</template>

<template id="register">
    <div>
        <h2>用户注册</h2>
        <p>手机号:<input type="text"></p>
        <p>身份证号:<input type="text"></p>
    </div>
</template>

<script src="./js/vue.js" type="text/javascript"></script>
<script type="text/javascript">
    Vue.component("login", {
        template: "#login"
    })
    Vue.component("register", {
        template: "#register"
    })
    var vm = new Vue({
        el: "#root"
    })
</script>

默认效果如下:

实现切换后的效果如下:

使用v-if和v-else切换

<div id="root">
    <a href="javascript:void(0)" @click="flag = true">登录</a>
    <a href="javascript:void(0)" @click="flag = false">注册</a>
    <login v-if="flag"></login>
    <register v-else></register>
</div>

<template id="login">
    <div>
        <h2>用户登录</h2>
        <p>用户名:<input type="text"></p>
        <p>密码:<input type="text"></p>
    </div>
</template>

<template id="register">
    <div>
        <h2>用户注册</h2>
        <p>手机号:<input type="text"></p>
        <p>身份证号:<input type="text"></p>
    </div>
</template>

<script src="./js/vue.js" type="text/javascript"></script>
<script type="text/javascript">
    Vue.component("login", {
        template: "#login"
    })
    Vue.component("register", {
        template: "#register"
    })
    var vm = new Vue({
        el: "#root",
        data: {
            flag: true
        }
    })
</script>

component元素实现组件切换

component元素是一个占位符, :is 属性用来指定要展示的组件名称

<component :is="componentId"></component>

需要注意的是,:is属性的值是组件名称字符串,需要按照如下的代码,才能将组件正常展示

<div id="root">	
    <a href="javascript:void(0)"  @click="flag=true">登录</a>
    <a href="" @click.prevent="flag=false">注册</a>
    <!-- component元素是一个占位符, :is 属性用来指定要展示的组件名称 -->
    <component :is="'login'"></component>
    <component :is="'register'"></component>
</div>

所以,如果使用<component>元素就要定一个变量

<div id="root">
    <a href="javascript:void(0)" @click="componentName='login'">登录</a>
    <a href="" @click.prevent="componentName='register'">注册</a>
    <!-- component元素是一个占位符, :is 属性用来指定要展示的组件名称 -->
    <component :is="componentName"></component>
</div>

<template id="login">
    <div>
        <h2>用户登录</h2>
        <p>用户名:<input type="text"></p>
        <p>密码:<input type="text"></p>
    </div>
</template>

<template id="register">
    <div>
        <h2>用户注册</h2>
        <p>手机号:<input type="text"></p>
        <p>身份证号:<input type="text"></p>
    </div>
</template>
<script type="text/javascript">
    Vue.component("login", {
        template: "#login"
    })
    Vue.component("register", {
        template: "#register"
    })
    var vm = new Vue({
        el: "#root",
        data: {
            componentName: "login"
        }
    })
</script>

组件过渡切换

官网地址:https://cn.vuejs.org/v2/guide/transitions.html#多个组件的过渡

根据官网代码,改造案例:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
    <title></title>
    <!-- 引入vue.js -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style>
        .component-fade-enter-active,
        .component-fade-leave-active {
            transition: all .3s ease;
        }

        .component-fade-enter,
        .component-fade-leave-to {
            opacity: 0;
            transform: translateX(150px)
        }
    </style>
</head>

<body>
    <div id="root">
        <a href="javascript:void(0)" @click="componentName='login'">登录</a>
        <a href="" @click.prevent="componentName='register'">注册</a>
        <!-- 添加 mode="out-in",意思是让过渡效果显示为一个消失了,另一个再进来 -->
        <!-- 添加name属性,是为了设置过渡样式 -->
        <transition name="component-fade" mode="out-in">
            <component :is="componentName"></component>
        </transition>
    </div>
    <template id="login">
        <div>
            <h2>用户登录</h2>
            <p>用户名:<input type="text"></p>
            <p>密码:<input type="text"></p>
        </div>
    </template>

    <template id="register">
        <div>
            <h2>用户注册</h2>
            <p>手机号:<input type="text"></p>
            <p>身份证号:<input type="text"></p>
        </div>
    </template>
    <script type="text/javascript">
        Vue.component("login", {
            template: "#login"
        })
        Vue.component("register", {
            template: "#register"
        })
        var vm = new Vue({
            el: "#root",
            data: {
                componentName: "login"
            }
        })
    </script>
</body>

</html>

六、组件传值

组件传值的遇到的问题

局部定义组件的方式,需要考虑Vue实例和组件之间的传值的问题,而子组件默认无法访问到父组件的数据和methods里方法。

<div id="root">
    <product-list></product-list>
</div>

<script src="./js/vue.js"></script>
<script type="text/javascript">
    var vm = new Vue({
        el: "#root",
        data: {
            msg: "Vue实例相当于内部组件的父组件"
        },
        methods: {},
        components: {
            productList: {
                template: '<h2>{{msg}}</h2>'
            }
        }
    })
</script>

浏览器里的显示效果如下:

父组件向子组件传值

通过属性绑定的形式,把需要传递给子组件的数据,以属性绑定的形式,传递到子组件内部,供子组件使用。

官网摘抄:

所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。

<div id="app">
  <h2>父组件内部的数据: {{message}}</h2>
  <p>
    <button type="button" @click="message += '@123'">修改父组件中的数据</button>
  </p>
  <!-- 传:在父组件中使用子组件时,通过子组件的属性进行传递 -->
  <sub-component v-bind:msg="message"></sub-component>
</div>
<template id="sub">
  <div>
    <h2>子组件内部的数据: {{username}}</h2>
    <h2>子组件接收父组件传递的数据: {{msg}}</h2>
    <p>
      <button type="button" @click="msg += '_321'">修改子组件中的数据</button>
    </p>
  </div>
</template>
<script src="./js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
  var subComponent = {
    template: "#sub",
    data() {
      return {
        username: "Tom"
      };
    },
    props: ["msg"]
  };
  let vm = new Vue({
    el: "#app",
    data: {
      message: "hello vuejs",
    },
    components: {
      subComponent
    }
  });
</script>

子组件向父组件传值

方式一

	1、使用v-on指令,将父组件中的函数与子组件绑定。
		v-on:子组件中调用函数的名称="父组件中的函数名称"

	2、子调用父函数。
		通过Vue对象中提供一个“触发函数”来实现在子组件内调用父组件的函数
		触发函数: $emit(父组件映射的函数名称, 调用父组件函数传递的参数)
<div id="app">
  <h2>父组件内部的数据: {{message}}</h2>
  <p>
    <button type="button" @click="message += '@123'">修改父组件中的数据</button>
  </p>
  <!--
  1.使用v-on指令,将父组件中的函数与子组件绑定,
  v-on:子组件中调用函数的名称="父组件中的函数名称"
  -->
  <sub-component v-bind:msg="message" v-on:test="changeVal"></sub-component>
</div>
<template id="sub">
  <div>
    <h2>子组件内部的数据: {{username}}</h2>
    <h2>子组件接收父组件传递的数据: {{msg}}</h2>
    <p><button type="button" @click="doChange">调用父组件中的函数</button></p>
  </div>
</template>
<script src="./js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
  var subComponent = {
    template: "#sub",
    data() {
      return {
        username: "Tom",
      };
    },
    props: ["msg"],
    methods: {
      doChange() {
        /**
* 2.子调用父函数
* 通过Vue对象中提供一个“触发函数”来实现在子组件内调用父组件的函数
* 触发函数: $emit(父组件映射的函数名称, 调用父组件函数传递的参数)
*
* 注意:在子向父传值时,无需修改子组件中的props数据
* 在子中调用$emit()修改父中data,父中的data一旦发生又立刻将新数据更新
到子
*/
        // this.msg = '你好,组件'
        this.$emit("test", "你好,组件");
      },
    },
  };
  let vm = new Vue({
    el: "#app",
    data: {
      message: "hello vuejs",
    },
    components: {
      subComponent,
    },
    methods: {
      changeVal(p) {
        console.log("changeVal函数执行了...");
        this.message = p;
      },
    },
  });
</script>

方式二

	1、v-bind指令+sync修饰符(同步修饰符):可以实现数据的“双向绑定”

	2、通过Vue对象中提供一个“触发函数”来实现
		$emit('update:Props中数据的名称', 传递的数据)
<div id="app">
  <h2>父组件内部的数据: {{message}}</h2>
  <p>
    <button type="button" @click="message += '@123'">修改父组件中的数据</button>
  </p>
  <!--
    1. v-bind指令+sync修饰符(同步修饰符):可以实现数据的“双向绑定”
    -->
  <sub-component v-bind:msg.sync="message"></sub-component>
</div>
<template id="sub">
  <div>
    <h2>子组件内部的数据: {{username}}</h2>
    <h2>子组件接收父组件传递的数据: {{msg}}</h2>
    <p><button type="button" @click="dataBack">回传数据</button></p>
  </div>
</template>

<script src="./js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
  var subComponent = {
    template: "#sub",
    data() {
      return {
        username: "Tom",
      };
    },
    props: ["msg"],
    methods: {
      dataBack() {
        /**
         * 2.通过Vue对象中提供一个“触发函数”来实现
         *
         * $emit('update:Props中数据的名称', 传递的数据)
         */
        this.$emit("update:msg", "你好,前端");
      },
    },
  };
  let vm = new Vue({
    el: "#app",
    data: {
      message: "hello vuejs",
    },
    components: {
      subComponent,
    },
  });

  // 组件传值
  // 1.父子传值:父data --> 子props
  // 父向子:通过v-bind传递数据,通过v-on绑定函数
  // 子向父:v-bind指令需要有.sync修饰符,通过this.$emit('update:更新props')回传数据
  // 2.路由传值
  // 3.vuex状态管理
</script>

七、Props

Props 是你可以在组件上注册的一些自定义特性。当一个值传递给一个 props 特性的时候,它就变成了那个组件实例的一个属性。

Props的大小写

HTML 中的 attribute 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名:

// 组件
Vue.component('my-component', {
	props: ['addTitle'],
	template: '<h3>{{ addTitle }}</h3>'
})

在HTML中是中划线的:

<my-component :add-title="'hello'"></my-component>

Props类型

到这里,我们只看到了以字符串数组形式列出的 props:

props: ['name', 'age', 'isLogin', 'hobby', 'address']

但是,通常你希望每个 props 都有指定的值类型。这时,你可以以对象形式列出 props,这些属性的名称和值分别是 props 各自的名称和类型:

props: {
    name: String,
    age: Number,
    isLogin: Boolean,
    hobby: Array,
    address: Object
}

示例代码:

<div id="app">
  <sub-component
    v-bind:msg="message"
    :username="username"
    :age="age"
    :gender="gender"
    :hobby="hobby"
    :address="address"
    :add-user="addUser"
    title="标题"
  ></sub-component>
</div>
<template id="sub">
  <div>
    <h2>子组件内部的数据: {{name}}</h2>
    <h2>子组件接收父组件的数据msg: {{msg}}</h2>
    <h2>子组件接收父组件的数据addUser: {{addUser}}</h2>
    <h2>子组件接收父组件的数据username: {{username}}</h2>
    <h2>子组件接收父组件的数据age: {{age}}</h2>
    <h2>子组件接收父组件的数据gender: {{gender}}</h2>
    <h2>子组件接收父组件的数据hobby: {{hobby}}</h2>
    <h2>子组件接收父组件的数据address: {{address}}</h2>
    <h2>子组件接收父组件的数据title: {{title}}</h2>
    <h2>子组件接收父组件的数据str: {{str}}</h2>
  </div>
</template>
<script src="./js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
  var subComponent = {
    template: "#sub",
    data() {
      return {
        name: "Tom",
      };
    },
    //props的值可以为数据,也可以是一个字面量对象
    //字面量对象的属性名为接收父向子传数据的变量名称
    //字面量对象的属性值为变量类型
    props: {
      msg: String,
      addUser: String,
      username: String,
      age: Number,
      gender: Boolean,
      hobby: Array,
      address: Object,
      title: String,
      str: {
        //数据类型,数据默认,数据校验...
        type: String,
        default: "你好",
        required: true,
      },
    },
  };
  let vm = new Vue({
    el: "#app",
    data: {
      message: "hello vuejs",
      addUser: "新增用户",
      username: "Jerry",
      age: 26,
      gender: true,
      hobby: ["读书", "运动", "游戏"],
      address: {
        city: "郑州市",
        street: "迎春街",
      },
    },
    components: {
      subComponent,
    },
  });
</script>

传递静态或动态Props

像这样,你已经知道了可以像这样给 props 传入一个静态的值:

<my-component title="数据列表"></my-component>

也可以通过 v-bind 动态赋值,例如:

<!-- 动态赋予一个变量的值 -->
<my-component v-bind:title="addTitle"></my-component>

<!-- 动态赋予一个复杂表达式的值 -->
<my-component v-bind:title="name + '的' + addTitle"></my-component>

注意:静态传值的类型只能为字符串

Props验证

可以为组件的 props 指定验证要求,例如你知道的这些类型。如果有一个需求没有被满足,则 Vue 会在浏览器控制台中警告你。这在开发一个会被别人用到的组件时尤其有帮助。

为了定制 prop 的验证方式,你可以为 props 中的值提供一个带有验证需求的对象,而不是一个字符串数组。例如:

Vue.component('my-component', {
    props: {
        // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
        propA: Number,
        // 多个可能的类型
        propB: [String, Number],
        // 必填的字符串
        propC: {
            type: String,
            required: true
        },
        // 带有默认值的数字
        propD: {
            type: Number,
            default: 100
        },
        // 带有默认值的对象
        propE: {
            type: Object,
            // 对象或数组默认值必须从一个工厂函数获取
            default: function () {
                return { message: 'hello' }
            }
        },
        // 自定义验证函数
        propF: {
        	validator: function (value) {
            // 这个值必须匹配下列字符串中的一个
            return ['success', 'warning', 'danger'].indexOf(value) !== -1
            }
         }
     }
})

八、插槽

插槽内容和编译作用域

Vue 实现了一套内容分发的 API,这套 API 的设计灵感源自 Web Components 规范草案,将 <slot>元素作为承载分发内容的出口。

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

<div id="app">
  <!--
  在使用组件时,组件标签内所有的内容都会被忽略
  props: 接收父组件传递的数据
  插槽: 父向子传递的html文本
  -->
  <sub-component :msg="message">hello</sub-component>
  <sub-component :msg="message">
    <h3>html元素</h3>
    <!--
  编译作用域:
  在父组件使用子组件时,在其标签内使用子组件的数据,这种情况是不允许的
  该插槽模板使用的数据与其他非插槽使用数据应在同一个作用域内
  -->
    <!-- <h3>@{{name}}@</h3> -->
  </sub-component>
</div>
<template id="sub">
  <div>
    <h2>组件数据</h2>
    <p>{{name}}</p>
    <p>{{msg}}</p>
    <!--
  通过<slot>标签来接收父组件向子传递的html文本
  -->
    <slot></slot>
  </div>
</template>
<script src="./js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
  var subComponent = {
    template: "#sub",
    data() {
      return {
        name: "Tom",
      };
    },
    props: ["msg"],
  };
  let vm = new Vue({
    el: "#app",
    data: {
      message: "hello vuejs",
    },
    components: {
      subComponent,
    },
  });
</script>

作为一条规则,请记住:

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

后备内容

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

<div id="app">
  <my-button>提交</my-button>
  <br />
  <my-button>登录</my-button>
  <br />
  <my-button>取消</my-button>
  <br />
  <my-button></my-button>
</div>
<template id="btn">
  <div>
    <button>
      <!--后备:插槽的默认文本-->
      <slot>后备内容</slot>
    </button>
  </div>
</template>
<script src="./js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
  var myButton = {
    template: "#btn",
  };
  let vm = new Vue({
    el: "#app",
    data: {
      message: "hello vuejs",
    },
    components: {
      myButton,
    },
  });
</script>

具名插槽

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

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

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

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

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

在向具名插槽提供内容的时候,我们可以在一个

posted @ 2023-11-04 17:28  城市炊烟  阅读(2)  评论(0编辑  收藏  举报