2025年3月15日 星期六 甲辰(龙)年 月十四 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > JavaScript

Vue组件开发指南

时间:02-13来源:作者:点击数:20
CDSY,CDSY.XYZ

1.1 什么是组件

组件 (Component)是 Vue.js 最强大的功能之一,组件是一个自定义元素或称为一个模块,包括所需的模板(HTML)、逻辑(JavaScript)和样式(CSS)。

组件化开发的特点:

  • 标准
  • 分治
  • 重用
  • 组合

组件也是有 全局(component) 与 局部(components) 之分。

1.2 组件的注册及其使用

在使用组件时需要注意以下几点:

  • 构造 Vue 实例时传入的各种选项大多数都可以在组件里使用,只有一个例外:data必须是函数,同时这个函数要求返回一个对象
  • data:{
  •  msg: 'hello world'
  • }
  • data: function(){
  •  return {
  •    msg: '你好世界'
  • }
  • }
  • 组件模板 template
    • 必须是单个根元素
    • <!-- 单个根元素 -->
    • <div>
    •  <ul>
    •    <li></li>
    •  </ul>
    •  <ul>
    •    <li></li>
    •  </ul>
    • </div>
    • <!-- 不符合单个根元素的情况 -->
    • <p></p>
    • <p></p>
    • 支持模板字符串形式
      • `${a}`
  • 组件名称命名方式
    • 短横线方式(推荐)
      • my-component
    • 大驼峰方式(只能在其他组件模板字符串中使用,不能在HTML模板中直接使用)
      • MyComponent

大驼峰式组件名不能在HTML模板中直接使用,如果需要在HTML模板中使用,需要将其进行特定规则转化:

  • 首字母从大写转为小写
  • 后续每遇到大写字母都要转化成小写并且在转化后的小写字母前加 -

例如, WoDeZuJian 这个大驼峰组件名在HTML中使用的时候需要写成 wo-de-zu-jian

1.2.1 全局组件

全局组件注册形式如下:

  • // 声明全局组件
  • Vue.component(componentName,{
  •  data: '组件数据',
  •  template: '组件模版内容'
  • })

上述示例中, component() 的第一个参数是 组件名 (实则可以看作是HTML标签名称),第二个参数是一个对象形式的选项,里面存放组件的声明信息。全局组件注册后,任何Vue实例都可以使用。

例如,有以下代码:

  • // 声明一个全局的HelloWorld组件
  • Vue.component('HelloWorld', {
  •  data: function(){
  •    return {
  •      msg: 'HelloWorld'
  •   }
  • },
  •  template: '<div>{{msg}}</div>'
  • });
  • <!DOCTYPE html>
  • <html lang="en">
  • <head>
  •  <meta charset="UTF-8">
  •  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  •  <title>01 全局注册组件</title>
  • </head>
  • <body>
  •  <div id="app">
  •    <!-- 3.使用组件 -->
  •    <!-- 像html标签一样使用组件
  •      a.在纯html模版中不可以使用大驼峰式的标签组件
  •      b.但是可以使用短横线的方式
  •      c.在vue的单文件组件中可以使用 大驼峰式的标签组件
  •    -->
  •    <my-header></my-header>
  •  </div>
  • </body>
  • <script src="lib/vue.js"></script>
  • <script>
  •  // 1.定义组件
  •  const Header = {
  •    // 定义组件时没有 el 选项,使用template代替
  •    template: `
  •              <div>
  •                <h1>这里是标题 - {{ title }}</h1>
  •                <button @click="add">加</button>{{ count }}
  •              </div>
  •              `,
  •    // data在组件中必须是一个函数 --- 作用域
  •    data () {
  •      return {
  •        title: 'VUE 权威指南',
  •        count: 10
  •     }
  •   },
  •    // 其余选项均保持一致
  •    methods: {
  •      add () {
  •        this.count += 10
  •     }
  •   }
  • }
  •  // 2.注册组件 - // 全局注册组件
  •  // Vue.component(组件名称,组件选项)
  •  // Vue.component('MyHeader', Header) // 大驼峰式命名
  •  Vue.component('my-header', Header) // 短横线方式命名
  •  new Vue({
  •    el: '#app'
  • })
  • </script>
  • </html>

发现组件的 template选项,如果代码过多,代码的可读性很差,所以可以提取模版信息

  • <!DOCTYPE html>
  • <html lang="en">
  • <head>
  •  <meta charset="UTF-8">
  •  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  •  <title>01 全局注册组件</title>
  • </head>
  • <body>
  •  <div id="app">
  •    <!-- 4.使用组件 -->
  •    <!-- 像html标签一样使用组件
  •      a.在纯html模版中不可以使用大驼峰式的标签组件
  •      b.但是可以使用短横线的方式
  •      c.在vue的单文件组件中可以使用 大驼峰式的标签组件
  •    -->
  •    <my-header></my-header>
  •  </div>
  • </body>
  • <script src="lib/vue.js"></script>
  • <!-- 1.定义组件的模版,通过id指示是哪个组件的
  •    组件模版应该写在页面的哪个位置 - 因为 template 是一个空标签
  •  -->
  • <template id="header">
  •  <div>
  •    <h1>这里是标题 - {{ title }}</h1>
  •    <button @click="add"></button>{{ count }}
  •  </div>
  • </template>
  • <script>
  •  // 2.定义组件
  •  const Header = {
  •    // 定义组件时没有 el 选项,使用template代替
  •    template: '#header',
  •    // data在组件中必须是一个函数 --- 作用域
  •    data () {
  •      return {
  •        title: 'VUE 权威指南',
  •        count: 10
  •     }
  •   },
  •    // 其余选项均保持一致
  •    methods: {
  •      add () {
  •        this.count += 10
  •     }
  •   }
  • }
  •  // 3.注册组件 - // 全局注册组件
  •  // Vue.component(组件名称,组件选项)
  •  // Vue.component('MyHeader', Header) // 大驼峰式命名
  •  Vue.component('my-header', Header) // 短横线方式命名
  •  new Vue({
  •    el: '#app'
  • })
  • </script>
  • </html>

1.定义组件的模版 <template id=""></template>

2.定义组件 const Com = { }

3.注册组件: 全局注册和局部注册

4.使用组件

1.2.2 局部组件

局部组件定义后只能在当前注册它的Vue实例中使用,其是通过某个 Vue 实例/组件的实例选项components 注册。

例如,有以下代码:

  • var Child = {
  •  template: '<div>A custom component!</div>'
  • }
  • new Vue({
  •  components: {
  •    // <my-component> 将只在父组件模板中可用
  •    'my-component': Child
  • }
  • })
  • <!DOCTYPE html>
  • <html lang="en">
  • <head>
  •  <meta charset="UTF-8">
  •  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  •  <title>03 局部注册组件</title>
  • </head>
  • <body>
  •  <div id="app">
  •    <!-- 4.使用组件 -->
  •    <!-- 像html标签一样使用组件
  •      a.在纯html模版中不可以使用大驼峰式的标签组件
  •      b.但是可以使用短横线的方式
  •      c.在vue的单文件组件中可以使用 大驼峰式的标签组件
  •    -->
  •    <my-header></my-header>
  •  </div>
  • </body>
  • <script src="lib/vue.js"></script>
  • <!-- 1.定义组件的模版,通过id指示是哪个组件的
  •    组件模版应该写在页面的哪个位置 - 因为 template 是一个空标签
  •  -->
  • <template id="header">
  •  <div>
  •    <h1>这里是标题 - {{ title }}</h1>
  •    <button @click="add"></button>{{ count }}
  •  </div>
  • </template>
  • <script>
  •  // 2.定义组件
  •  const Header = {
  •    // 定义组件时没有 el 选项,使用template代替
  •    template: '#header',
  •    // data在组件中必须是一个函数 --- 作用域
  •    data () {
  •      return {
  •        title: 'VUE 权威指南',
  •        count: 10
  •     }
  •   },
  •    // 其余选项均保持一致
  •    methods: {
  •      add () {
  •        this.count += 10
  •     }
  •   }
  • }
  •  // 3.注册组件 - // 全局注册组件
  •  // Vue.component(组件名称,组件选项)
  •  // Vue.component('MyHeader', Header) // 大驼峰式命名
  •  // Vue.component('my-header', Header) // 短横线方式命名
  •  new Vue({
  •    el: '#app',
  •    components: { // 3.局部注册组件
  •      // MyHeader: Header
  •      'my-header': Header
  •   }
  • })
  • </script>
  • </html>
1.2.3 组件的使用

在HTML模板中,组件以一个自定义标签的形式存在,起到占位符的功能。通过Vue.js的声明式渲染后,占位符将会被替换为实际的内容,下面是一个最简单的模块示例:

  • <div id="app">
  •  <my-component></my-component>
  • </div>

也可以在一个组件的组件模板中去使用其他已经注册的组件

  • <!DOCTYPE html>
  • <html lang="en">
  • <head>
  •  <meta charset="UTF-8">
  •  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  •  <title>04 封装swiper</title>
  •  <link rel="stylesheet" href="lib/swiper-bundle.min.css" />
  •  <style>
  •    .swiper-container {
  •      width: 100%;
  •      height: 300px;
  •   }  
  •  </style>
  • </head>
  • <body>
  •  <div id="app">
  •    <!-- 4.使用组件 -->
  •    <my-swiper></my-swiper>
  •  </div>
  • </body>
  • <script src="lib/vue.js"></script>
  • <script src="lib/axios.min.js"></script>
  • <script src="lib/swiper-bundle.min.js"></script>
  • <!-- 1.定义组件的模版 -->
  • <template id="mySwiper">
  •  <div class="swiper-container">
  •    <div class="swiper-wrapper">
  •        <div class="swiper-slide" v-for="item of list" :key="item.bannerid">
  •          <img :src="item.img" alt="">
  •        </div>
  •    </div>
  •    <!-- 如果需要分页器 -->
  •    <div class="swiper-pagination"></div>
  •    
  •    <!-- 如果需要导航按钮 -->
  •    <div class="swiper-button-prev"></div>
  •    <div class="swiper-button-next"></div>
  •    
  •    <!-- 如果需要滚动条 -->
  •    <div class="swiper-scrollbar"></div>
  •   </div>
  • </template>
  • <script>
  •  // 2.定义组件
  •  const SwiperCom = {
  •    template: '#mySwiper',
  •    data () {
  •      return {
  •        list: []
  •     }
  •   },
  •    mounted () {
  •      axios.get('http://121.89.205.189/api/banner/list')
  •       .then(res => {
  •          console.log(res.data.data)
  •          this.list = res.data.data
  •                  
  •       })
  •   },
  •    updated() {
  •      var mySwiper = new Swiper ('.swiper-container', {
  •        loop: true, // 循环模式选项
  •        
  •        // 如果需要分页器
  •        pagination: {
  •          el: '.swiper-pagination',
  •       },
  •        
  •        // 如果需要前进后退按钮
  •        navigation: {
  •          nextEl: '.swiper-button-next',
  •          prevEl: '.swiper-button-prev',
  •       },
  •        
  •        // 如果需要滚动条
  •        scrollbar: {
  •          el: '.swiper-scrollbar',
  •       },
  •     })
  •   }
  • }
  •  // 3.注册组件 - // 全局注册组件
  •  new Vue({
  •    el: '#app',
  •    components: { // 3.局部注册组件
  •      MySwiper: SwiperCom
  •   }
  • })
  • </script>
  • </html>

1.3 组件间传值

如前面介绍组件时所说,组件有 分治 的特点,每个组件之间具有一定的独立性,但是在实际工作中使用组件的时候有互相之间传递数据的需求,此时就得考虑如何进行 组件间传值 的问题了。

1.3.1 父->子传值

父子组件

  • <!DOCTYPE html>
  • <html lang="en">
  • <head>
  •  <meta charset="UTF-8">
  •  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  •  <title>05 父子组件</title>
  • </head>
  • <body>
  •  <div id="app">
  •    <my-parent></my-parent>
  •  </div>
  • </body>
  • <template id="parent">
  •  <div>
  •    <h1>父组件</h1>
  •    <my-child></my-child>
  •  </div>
  • </template>
  • <template id="child">
  •  <div>
  •    <h3>子组件</h3>
  •  </div>
  • </template>
  • <script src="lib/vue.js"></script>
  • <script>
  •  const Child = {
  •    template: '#child'
  • }
  •  const Parent = {
  •    template: '#parent',
  •    components: {
  •      MyChild: Child
  •   }
  • }
  •  // 谁用谁注册
  •  new Vue({
  •    el: '#app',
  •    components: {
  •      MyParent: Parent
  •   }
  • })
  • </script>
  • </html>
  • 父组件以属性的形式绑定值到子组件身上
  • 子组件通过使用属性props接收
    • props是单向绑定的(只读属性):当父组件的属性变化时,将传导给子组件,但是反过来不会
    • props属性支持两种常见的写法形式
      • 数组
        • 优点:书写简单
        • 缺点:不能设置默认值、数据类型
      • 对象
        • 优点:可以设置数据默认值与数据类型
        • 缺点:写法复杂
  • <!DOCTYPE html>
  • <html lang="en">
  • <head>
  •  <meta charset="UTF-8">
  •  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  •  <title>06 父组件给子组件传值1</title>
  • </head>
  • <body>
  •  <div id="app">
  •    <my-parent></my-parent>
  •  </div>
  • </body>
  • <template id="parent">
  •  <div>
  •    <h1>父组件</h1>
  •    <!-- 1.父组件在调用子组件的地方,添加自定义的属性 -->
  •    <!-- 如果自定义的属性的值是变量,boolean类型,number类型,对象,数组,
  •      null或者undefined,需要使用绑定属性 -->
  •    <my-child :msg="msg" :flag="true" :num="100" :obj="{a:1}" :arr="[1, 2, 3]"></my-child>
  •  </div>
  • </template>
  • <template id="child">
  •  <div>
  •    <h3>子组件</h3>
  •   {{ msg }} - {{ flag }} -- {{ num }} -- {{ obj }} -- {{ arr }}
  •  </div>
  • </template>
  • <script src="lib/vue.js"></script>
  • <script>
  •  // 在子组件定义的地方,添加props选项,props可以有两大类的使用方法
  •  // 数组
  •  //   数组的元素就是自定义的属性名,这样就可以通过自定义的属性名渲染子组件的数据
  •  // 对象,对象的写法又分为两大类写法
  •  const Child = {
  •    props: ['msg', 'flag', 'num', 'obj', 'arr'],
  •    template: '#child'
  • }
  •  const Parent = {
  •    template: '#parent',
  •    data () {
  •      return {
  •        msg: 'hello msg'
  •     }
  •   },
  •    components: {
  •      MyChild: Child
  •   }
  • }
  •  // 谁用谁注册
  •  new Vue({
  •    el: '#app',
  •    components: {
  •      MyParent: Parent
  •   }
  • })
  • </script>
  • </html>
  • <!DOCTYPE html>
  • <html lang="en">
  • <head>
  • <meta charset="UTF-8">
  • <meta name="viewport" content="width=device-width, initial-scale=1.0">
  • <title>07 父组件给子组件传值2</title>
  • </head>
  • <body>
  • <div id="app">
  •    <my-parent></my-parent>
  • </div>
  • </body>
  • <template id="parent">
  • <div>
  •    <h1>父组件</h1>
  •    <!-- 1.父组件在调用子组件的地方,添加自定义的属性 -->
  •    <!-- 如果自定义的属性的值是变量,boolean类型,number类型,对象,数组,
  •      null或者undefined,需要使用绑定属性 -->
  •    <my-child :msg="msg" :flag="true" :num="100" :obj="{a:1}" :arr="[1, 2, 3]"></my-child>
  •  </div>
  • </template>
  • <template id="child">
  • <div>
  •   <h3>子组件</h3>
  •   {{ msg }} - {{ flag }} -- {{ num }} -- {{ obj }} -- {{ arr }}
  •  </div>
  • </template>
  • <script src="lib/vue.js"></script>
  • <script>
  • // 在子组件定义的地方,添加props选项,props可以有两大类的使用方法
  • // 数组
  • //   数组的元素就是自定义的属性名,这样就可以通过自定义的属性名渲染子组件的数据
  • // 对象,对象的写法又分为两大类写法
  • //   对象的key值为自定义的属性名,value值为数据类型,这样就可以通过自定义的属性名渲染子组件的数据
  • const Child = {
  •    // props: ['msg', 'flag', 'num', 'obj', 'arr'],
  •    props: {
  •      msg: String,
  •      flag: Boolean,
  •      num: Number,
  •      obj: Object,
  •      arr: Array
  •   },
  •    template: '#child'
  • }
  • const Parent = {
  •   template: '#parent',
  •    data () {
  •      return {
  •        msg: 'hello msg'
  •     }
  •   },
  •    components: {
  •      MyChild: Child
  •   }
  • }
  • // 谁用谁注册
  • new Vue({
  •    el: '#app',
  •    components: {
  •      MyParent: Parent
  •   }
  • })
  • </script>
  • </html>
  • <!DOCTYPE html>
  • <html lang="en">
  • <head>
  • <meta charset="UTF-8">
  • <meta name="viewport" content="width=device-width, initial-scale=1.0">
  • <title>08 父组件给子组件传值3</title>
  • </head>
  • <body>
  • <div id="app">
  •    <my-parent></my-parent>
  • </div>
  • </body>
  • <template id="parent">
  • <div>
  •    <h1>父组件</h1>
  •    <!-- 1.父组件在调用子组件的地方,添加自定义的属性 -->
  •    <!-- 如果自定义的属性的值是变量,boolean类型,number类型,对象,数组,
  •      null或者undefined,需要使用绑定属性 -->
  •    <my-child :msg="msg" :flag="true" :num="100" :obj="{a:1}" :arr="[1, 2, 3]"></my-child>
  •    <my-child :msg="msg" :flag="true" :arr="[4, 5, 6]"></my-child>
  •  </div>
  • </template>
  • <template id="child">
  • <div>
  •   <h3>子组件</h3>
  •   {{ msg }} - {{ flag }} -- {{ num }} -- {{ obj }} -- {{ arr }}
  •  </div>
  • </template>
  • <script src="lib/vue.js"></script>
  • <script>
  • // 在子组件定义的地方,添加props选项,props可以有两大类的使用方法
  • // 数组
  • //   数组的元素就是自定义的属性名,这样就可以通过自定义的属性名渲染子组件的数据
  • // 对象,对象的写法又分为两大类写法
  • //   对象的key值为自定义的属性名,value值为数据类型,这样就可以通过自定义的属性名渲染子组件的数据
  • //   对象的key值为自定义的属性名,value值为新的一个对象
  • //       对象的key值可以为type,value值则为数据类型
  • //       对象的key值可以为default,value值则为属性的默认值(如果默认值是对象和数组,需要使用函数返回他们)
  • //       对象的key值可以为 required,value值则表示该属性是必须传递的数据
  • //       对象的key值可以为 validator, value值则表示可以对该属性进行验证
  •  const Child = {
  •    // props: ['msg', 'flag', 'num', 'obj', 'arr'],
  •    // props: {
  •    //   msg: String,
  •    //   flag: Boolean,
  •    //   num: Number,
  •    //   obj: Object,
  •    //   arr: Array
  •    // },
  •    props: {
  •      msg: {
  •        type: String
  •     },
  •      flag: Boolean,
  •      num: {
  •        type: Number,
  •        default: 1,
  •        validator (val) {
  •          if (val > 10) {
  •            console.log('ok')
  •         } else {
  •            console.log('fail')
  •         }
  •          return val > 10
  •       }
  •     },
  •      obj: {
  •        type: Object,
  •        default () { return { a: 10000 }}
  •     },
  •      arr: {
  •        type: Array,
  •        required: true
  •     }
  •   },
  •    template: '#child'
  • }
  •  const Parent = {
  •    template: '#parent',
  •    data () {
  •     return {
  •       msg: 'hello msg'
  •     }
  •   },
  •    components: {
  •      MyChild: Child
  •   }
  • }
  •  // 谁用谁注册
  •  new Vue({
  •    el: '#app',
  •   components: {
  •     MyParent: Parent
  •   }
  • })
  • </script>
  • </html>

自己整理话术:

1.3.2 子->父传值
  • 子组件模版内容中用 $emit() 定义 自定义事件 , $emit() 方法有2个参数
    • 第一个参数为自定义的事件名称
    • 第二个参数为需要传递的数据(可选)
  • 父组件模板内容中的子组件占位标签上用v-on(或@)绑定子组件定义的自定义事件名,监听子组件的事件,实现通信
  • <!DOCTYPE html>
  • <html lang="en">
  • <head>
  •  <meta charset="UTF-8">
  •  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  •  <title>09 子组件给父组件传值</title>
  • </head>
  • <body>
  •  <div id="app">
  •    <my-parent></my-parent>
  •  </div>
  • </body>
  • <template id="parent">
  •  <div>
  •    <h1>父组件</h1>
  •    <!-- 父组件在调用子组件的地方,绑定一个自定义的事件
  •      这个事件的实现由父组件负责,事件的默认参数就是子组件传递给父组件的值
  •    -->
  •    <my-child @my-event="getChildData"></my-child>
  •  </div>
  • </template>
  • <template id="child">
  •  <div>
  •    <h3>子组件</h3>
  •    <button @click="sendData">发送数据</button>
  •  </div>
  • </template>
  • <script src="lib/vue.js"></script>
  • <script>
  •  const Child = {
  •    template: '#child',
  •    // 在子组件的某一个事件内部,通过this.$emit('自定义的事件名', 参数)完成传值
  •    methods: {
  •      sendData () {
  •        this.$emit('my-event', 10000)
  •     }
  •   }
  • }
  •  const Parent = {
  •    template: '#parent',
  •    components: {
  •      MyChild: Child
  •   },
  •    methods: {
  •      getChildData (val) {
  •        console.log(val)
  •     }
  •   }
  • }
  •  // 谁用谁注册
  •  new Vue({
  •    el: '#app',
  •    components: {
  •      MyParent: Parent
  •   }
  • })
  • </script>
  • </html>
1.3.3 EventBus

EventBus又被称之为中央事件总线

在Vue中通过单独的 事件中心 来管理非 父子关系 组件(兄弟)间的通信:

公众号千千万,都得先关注公众号,一旦发送消息,就可以收到消息 - 专注交流一百年

核心步骤

  • 建立事件中心
  • const eventBus = new Vue()
  • 传递数据
  • eventBus.$emit('自定义事件名',传递的数据)
  • 接收数据
  • eventBus.$on('自定义事件名'[,callback])
  • 销毁事件中心
  • eventBus.$off('自定义事件名')

先建立事件中心 const bus = new Vue()

在需要接受数据的地方先监听自定义事件以及接受数据的回调函数bus.$on('my-event', (data) => {})

在需要传递数据的地方提交 自定义事件以及参数 bus.$emit('my-event', params)

  • <!DOCTYPE html>
  • <html lang="en">
  • <head>
  •  <meta charset="UTF-8">
  •  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  •  <title>10 非父子组件传值 - 兄弟组件之间传值</title>
  • </head>
  • <body>
  •  <div id="app">
  •    <my-content></my-content>
  •    <my-footer></my-footer>
  •  </div>
  • </body>
  • <template id="content">
  •  <div>
  •   {{ name }}
  •  </div>
  • </template>
  • <template id="footer">
  •  <ul>
  •    <li @click="changeName('首页')">首页</li>
  •    <li @click="changeName('分类')">分类</li>
  •    <li @click="changeName('购物车')">购物车</li>
  •    <li @click="changeName('我的')">我的</li>
  •  </ul>
  • </template>
  • <script src="lib/vue.js"></script>
  • <script>
  •  // 注意:先监听才能接收到数据(得先关注公众号才能接收到消息)
  •  // 创建vue的实例作为中央事件总线 bus
  •  const bus = new Vue()
  •  const Content = {
  •    template: '#content',
  •    data () {
  •      return {
  •        name: '首页'
  •     }
  •   },
  •    mounted () {
  •      // 在需要监听数据的地方,通过bus.$on('自定义的事件',回调函数)用来接收数据,
  •      // 回调函数参数即为兄弟组件传递过来的值
  •      bus.$on('my-event', (val) => {
  •        this.name = val
  •     })
  •   }
  • }
  •  const Footer = {
  •    template: '#footer',
  •    methods: {
  •      changeName (val) {
  •        // 在需要传值的地方,通过bus.$emit('自定义的事件',参数)完成传值操作
  •        bus.$emit('my-event', val)
  •     }
  •   }
  • }
  •  // 谁用谁注册
  •  new Vue({
  •    el: '#app',
  •    components: {
  •      MyContent: Content,
  •      MyFooter: Footer
  •   }
  • })
  • </script>
  • </html>
1.3.4 ref

ref 属性被用来给元素或子组件注册引用信息,引用信息将会注册在父组件的 $refs 对象上。

如果在普通的 DOM 元素上使用 ref 属性,则引用指向的就是 DOM 元素;

如果 ref 属性用在子组件上,引用就指向子组件实例

  • ref 放在标签上,拿到的是原生节点。
  • ref 放在组件上 拿到的是组件实例
  • 原理:在父组件中通过 ref 属性(会被注册到父组件的 $refs 对象上)拿到组件/DOM对象,从而得到组件/DOM中的所有的信息,也包括值
  • <!DOCTYPE html>
  • <html lang="en">
  • <head>
  •  <meta charset="UTF-8">
  •  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  •  <title>11 Ref</title>
  • </head>
  • <body>
  •  <div id="app">
  •    <!-- ref属性既可以使用到 DOM元素,也可以使用到组件
  •    DOM元素 this.$refs 获取到DOM组成的对象
  •    组件上   this.$refs 获取到相关子组件组成的对象
  •    -->
  •    <div ref="smile">😂</div>
  •    <div ref="cry">😭</div>
  •    <my-content ref="com"></my-content>
  •    <button @click="getDOMData">获取值</button>
  •  </div>
  • </body>
  • <template id="content">
  •  <div>
  •   {{ name }}
  •  </div>
  • </template>
  • <script src="lib/vue.js"></script>
  • <script>
  •  const Content = {
  •    template: '#content',
  •    data () {
  •      return {
  •        name: '首页'
  •     }
  •   }
  • }
  •  
  •  // 我是***他父亲
  •  new Vue({
  •    el: '#app',
  •    components: {
  •      MyContent: Content
  •   },
  •    methods: {
  •      getDOMData () {
  •        console.log(this.$refs) // 获取到所有的ref属性
  •        console.log(this.$refs.smile.innerHTML)
  •        console.log(this.$refs.cry.innerHTML)
  •        console.log(this.$refs.com) // 获取到子组件的实例
  •        console.log(this.$refs.com.name) // 直接在父组件中调用子组件中属性和方法
  •     }
  •   },
  • })
  • </script>
  • </html>

注意:

ref 属性这种获取子元素/组件的方式虽然写法简单,容易上手,但是其由于权限过于开放,不推荐使用,有安全问题。(不仅可以获取值,还可以获取其他所有的元素/组件的数据,甚至可以修改这些数据。)

1.3.5 parent

可以通过$parent直接获取到父组件的实例

  • <!DOCTYPE html>
  • <html lang="en">
  • <head>
  •  <meta charset="UTF-8">
  •  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  •  <title>12 parent</title>
  • </head>
  • <body>
  •  <div id="app">
  •    <!-- $parent可以直接在子组件中获取到父组件的实例的属性和方法
  •    -->
  •    <div ref="smile">😂</div>
  •    <div ref="cry">😭</div>
  •    <my-content ref="com"></my-content>
  •  </div>
  • </body>
  • <template id="content">
  •  <div>
  •   {{ name }}
  •   {{ $parent.msg }}
  •    <button @click="getData">通过parent获取父组件的数据</button>
  •  </div>
  • </template>
  • <script src="lib/vue.js"></script>
  • <script>
  •  const Content = {
  •    template: '#content',
  •    data () {
  •      return {
  •        name: '首页'
  •     }
  •   },
  •    methods: {
  •      getData () {
  •        console.log(this.$parent)
  •        console.log(this.$parent.msg)
  •        this.$parent.fn()
  •     }
  •   },
  • }
  •  
  •  // 我爸是李刚
  •  new Vue({
  •    el: '#app',
  •    components: {
  •      MyContent: Content
  •   },
  •    data: {
  •      msg: 'hello msg'
  •   },
  •    methods: {
  •      fn () {
  •        console.log(110)
  •     }
  •   },
  • })
  • </script>
  • </html>

如果需要在组件的结构中访问父组件的属性和方法,不需要添加this,但是也可以添加

1.3.6 祖先组件传递后代组件

通过 provide + inject 完成传值

  • <!DOCTYPE html>
  • <html lang="en">
  • <head>
  •  <meta charset="UTF-8">
  •  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  •  <title>01 祖先组件传值给后代组件</title>
  • </head>
  • <body>
  •  <div id="app">
  •    <com></com>
  •  </div>
  • </body>
  • <template id="com">
  •  <div>
  •   后代组件 - {{ theme }}
  •  </div>
  • </template>
  • <script src="lib/vue.js"></script>
  • <script>
  •  const Com = {
  •    inject: ['theme'],
  •    template: '#com'
  • }
  •  new Vue({
  •    el: '#app',
  •    data: {},
  •    components: {
  •      Com
  •   },
  •    provide: {
  •      theme: 'dark'
  •   }
  • })
  • </script>
  • </html>
  • <!DOCTYPE html>
  • <html lang="en">
  • <head>
  •  <meta charset="UTF-8">
  •  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  •  <title>02 祖先组件传值给后代组件</title>
  • </head>
  • <body>
  •  <div id="app">
  •    <com></com>
  •  </div>
  • </body>
  • <template id="com">
  •  <div>
  •   后代组件 - {{ theme }} -- {{ message }}
  •  </div>
  • </template>
  • <script src="lib/vue.js"></script>
  • <script>
  •  const Com = {
  •    inject: ['theme', 'message'], // inject 还可以是 对象,类比 props中的对象
  •    template: '#com'
  • }
  •  new Vue({
  •    el: '#app',
  •    data: {
  •      msg: 'hello msg'
  •   },
  •    components: {
  •      Com
  •   },
  •    provide () { // 如果数据中包含组件的变量,使用 返回对象的 provide 函数
  •      return {
  •        theme: 'light',
  •        message: this.msg
  •     }
  •   }
  • })
  •  // 状态管理器
  • </script>
  • </html>

provide 和 inject 主要在开发高阶插件/组件库时使用。并不推荐用于普通应用程序代码中。

1.4 动态组件

通过分支条件判断实现选项卡切换

  • <body>
  •  <div id="app">
  •    <home v-if="type==='home'"></home>
  •    <kind v-else-if="type==='kind'"></kind>
  •    <cart v-else-if="type==='cart'"></cart>
  •    <user v-else></user>
  •    <ul>
  •      <li @click="goPage('home')">首页</li>
  •      <li @click="goPage('kind')">分类</li>
  •      <li @click="goPage('cart')">购物车</li>
  •      <li @click="goPage('user')">我的</li>
  •    </ul>
  •  </div>
  • </body>
  • <script src="lib/vue.js"></script>
  • <script>
  •  const Home = { template: '<div>首页组件</div>' }
  •  const Kind = { template: '<div>分类组件</div>' }
  •  const Cart = { template: '<div>购物车组件</div>' }
  •  const User = { template: '<div>我的组件</div>' }
  •  new Vue({
  •    el: '#app',
  •    data: {
  •      type: 'home'
  •   },
  •    components: {
  •      home: Home,
  •      kind: Kind,
  •      cart: Cart,
  •      user: User,
  •   },
  •    methods: {
  •      goPage (type) {
  •        this.type = type
  •     }
  •   }
  • })
  • </script>

通过使用保留的 <component> 元素,动态地绑定到它的 is 特性,我们让多个组件可以使用同一个挂载点,并动态切换。

  • <!DOCTYPE html>
  • <html lang="en">
  • <head>
  •  <meta charset="UTF-8">
  •  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  •  <title>04 动态组件</title>
  • </head>
  • <body>
  •  <div id="app">
  •    <!-- <home v-if="type==='home'"></home>
  •    <kind v-else-if="type==='kind'"></kind>
  •    <cart v-else-if="type==='cart'"></cart>
  •    <user v-else></user> -->
  •    <!-- type 的值是组件的名称 --- 组件标签 -->
  •    <component :is="type"></component>
  •    <ul>
  •      <li @click="goPage('home')">首页</li>
  •      <li @click="goPage('kind')">分类</li>
  •      <li @click="goPage('cart')">购物车</li>
  •      <li @click="goPage('user')">我的</li>
  •    </ul>
  •  </div>
  • </body>
  • <script src="lib/vue.js"></script>
  • <script>
  •  const Home = { template: '<div>首页组件</div>' }
  •  const Kind = { template: '<div>分类组件</div>' }
  •  const Cart = { template: '<div>购物车组件</div>' }
  •  const User = { template: '<div>我的组件</div>' }
  •  new Vue({
  •    el: '#app',
  •    data: {
  •      type: 'home'
  •   },
  •    components: {
  •      home: Home,
  •      kind: Kind,
  •      cart: Cart,
  •      user: User,
  •   },
  •    methods: {
  •      goPage (type) {
  •        this.type = type
  •     }
  •   }
  • })
  • </script>
  • </html>

思考:如果每个组件中都有一个输入框,点击切换时输入不同的内容,然后再切换,查看效果

keep-alive的作用:

keep-alive 可以将已经切换出去的非活跃组件保留在内存中。如果把切换出去的组件保留在内存中,可以保留它的状态,避免重新渲染。

  • <!DOCTYPE html>
  • <html lang="en">
  • <head>
  •  <meta charset="UTF-8">
  •  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  •  <title>05 动态组件</title>
  • </head>
  • <body>
  •  <div id="app">
  •    <!-- type 的值是组件的名称 --- 组件标签 -->
  •    <!-- 默认情况下,动态组件在切换时会触发组件的销毁和重建 -->
  •    <!-- 可以使用 keep-alive 组件解决这个问题
  •      可以缓存组件的状态,避免了组件的销毁和重建
  •    -->
  •    <keep-alive>
  •      <component :is="type"></component>
  •    </keep-alive>
  •    <ul>
  •      <li @click="goPage('home')">首页</li>
  •      <li @click="goPage('kind')">分类</li>
  •      <li @click="goPage('cart')">购物车</li>
  •      <li @click="goPage('user')">我的</li>
  •    </ul>
  •  </div>
  • </body>
  • <script src="lib/vue.js"></script>
  • <script>
  •  const Home = {
  •    template: '<div>首页组件 <input type="text"/></div>',
  •    mounted () { console.log('home mounted') },
  •    destroyed() {console.log('home destroyed')},
  • }
  •  const Kind = {
  •    template: '<div>分类组件 <input type="text"/></div>',
  •    mounted () { console.log('kind mounted') },
  •    destroyed() {console.log('kind destroyed')}
  • }
  •  const Cart = {
  •    template: '<div>购物车组件 <input type="text"/></div>',
  •    mounted () { console.log('cart mounted') },
  •    destroyed() {console.log('cart destroyed')}
  • }
  •  const User = {
  •    template: '<div>我的组件 <input type="text"/></div>',
  •    mounted () { console.log('user mounted') },
  •    destroyed() {console.log('user destroyed')}
  • }
  •  new Vue({
  •    el: '#app',
  •    data: {
  •      type: 'home'
  •   },
  •    components: {
  •      home: Home,
  •      kind: Kind,
  •      cart: Cart,
  •      user: User,
  •   },
  •    methods: {
  •      goPage (type) {
  •        this.type = type
  •     }
  •   }
  • })
  • </script>
  • </html>
  • <!DOCTYPE html>
  • <html lang="en">
  • <head>
  •  <meta charset="UTF-8">
  •  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  •  <title>06 动态组件钩子</title>
  • </head>
  • <body>
  •  <div id="app">
  •    <!-- type 的值是组件的名称 --- 组件标签 -->
  •    <!-- 默认情况下,动态组件在切换时会触发组件的销毁和重建 -->
  •    <!-- 可以使用 keep-alive 组件解决这个问题
  •      可以缓存组件的状态,避免了组件的销毁和重建
  •    -->
  •    <!--
  •      使用了keep-alive 数据请求在activated,否则可以在 created / mounted
  •      activated   请求数据
  •      deactivated
  •     -->
  •    <keep-alive>
  •      <component :is="type"></component>
  •    </keep-alive>
  •    <ul>
  •      <li @click="goPage('home')">首页</li>
  •      <li @click="goPage('kind')">分类</li>
  •      <li @click="goPage('cart')">购物车</li>
  •      <li @click="goPage('user')">我的</li>
  •    </ul>
  •  </div>
  • </body>
  • <script src="lib/vue.js"></script>
  • <script>
  •  const Home = {
  •    template: '<div>首页组件 <input type="text"/></div>',
  •    mounted () { console.log('home mounted') },
  •    destroyed() {console.log('home destroyed')},
  •    activated() { console.log('home activated')},
  •    deactivated() {console.log('home deactivated')},
  • }
  •  const Kind = {
  •    template: '<div>分类组件 <input type="text"/></div>',
  •    mounted () { console.log('kind mounted') },
  •    destroyed() {console.log('kind destroyed')},
  •    activated() { console.log('kind activated')},
  •    deactivated() {console.log('kind deactivated')},  
  • }
  •  const Cart = {
  •    template: '<div>购物车组件 <input type="text"/></div>',
  •    mounted () { console.log('cart mounted') },
  •    destroyed() {console.log('cart destroyed')},
  •    activated() { console.log('cart activated')},
  •    deactivated() {console.log('cart deactivated')},  
  • }
  •  const User = {
  •    template: '<div>我的组件 <input type="text"/></div>',
  •    mounted () { console.log('user mounted') },
  •    destroyed() {console.log('user destroyed')},
  •    activated() { console.log('user activated')},
  •    deactivated() {console.log('user deactivated')},  
  • }
  •  new Vue({
  •    el: '#app',
  •    data: {
  •      type: 'home'
  •   },
  •    components: {
  •      home: Home,
  •      kind: Kind,
  •      cart: Cart,
  •      user: User,
  •   },
  •    methods: {
  •      goPage (type) {
  •        this.type = type
  •     }
  •   }
  • })
  • </script>
  • </html>

思考:使用keep-alive 看似保留了所有的状态,但是如果某一个组件不要保留状态呢

  • <!DOCTYPE html>
  • <html lang="en">
  • <head>
  •  <meta charset="UTF-8">
  •  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  •  <title>06 动态组件钩子</title>
  • </head>
  • <body>
  •  <div id="app">
  •    <!-- 可以给 keep-alive 添加属性,表示需要缓存的组件
  •    include - 字符串或正则表达式。只有名称匹配的组件会被缓存。
  •    exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
  •    max - 数字。最多可以缓存多少组件实例。
  •    -->
  •    <!-- 逗号分隔字符串、正则表达式或一个数组来 -->
  •    <!-- 匹配首先检查组件自身的 name 选项,如果 name 选项不可用,则匹配它的局部注册名称 -->
  •    <!-- 逗号分隔字符串,逗号后不要加空格 -->
  •    <!-- <keep-alive include="ahome,akind">
  •      <component :is="type"></component>
  •    </keep-alive> -->
  •    <!-- 正则表达式: 绑定属性 -->
  •    <!-- <keep-alive :include="/ahome|akind|auser/">
  •      <component :is="type"></component>
  •    </keep-alive> -->
  •    <!-- 数组 -->
  •    <keep-alive :include="['acart', 'user']">
  •      <component :is="type"></component>
  •    </keep-alive>
  •    <!-- 匹配首先检查组件自身的 name 选项,如果 name 选项不可用,则匹配它的局部注册名称 -->
  •    <ul>
  •      <li @click="goPage('home')">首页</li>
  •      <li @click="goPage('kind')">分类</li>
  •      <li @click="goPage('cart')">购物车</li>
  •      <li @click="goPage('user')">我的</li>
  •    </ul>
  •  </div>
  • </body>
  • <script src="lib/vue.js"></script>
  • <script>
  •  const Home = {
  •    name: 'ahome',
  •    template: '<div>首页组件 <input type="text"/></div>',
  •    mounted () { console.log('home mounted') },
  •    destroyed() {console.log('home destroyed')},
  •    activated() { console.log('home activated')},
  •    deactivated() {console.log('home deactivated')},
  • }
  •  const Kind = {
  •    name: 'akind',
  •    template: '<div>分类组件 <input type="text"/></div>',
  •    mounted () { console.log('kind mounted') },
  •    destroyed() {console.log('kind destroyed')},
  •    activated() { console.log('kind activated')},
  •    deactivated() {console.log('kind deactivated')},  
  • }
  •  const Cart = {
  •    name: 'acart',
  •    template: '<div>购物车组件 <input type="text"/></div>',
  •    mounted () { console.log('cart mounted') },
  •    destroyed() {console.log('cart destroyed')},
  •    activated() { console.log('cart activated')},
  •    deactivated() {console.log('cart deactivated')},  
  • }
  •  const User = {
  •    // name: 'auser',
  •    template: '<div>我的组件 <input type="text"/></div>',
  •    mounted () { console.log('user mounted') },
  •    destroyed() {console.log('user destroyed')},
  •    activated() { console.log('user activated')},
  •    deactivated() {console.log('user deactivated')},  
  • }
  •  new Vue({
  •    el: '#app',
  •    data: {
  •      type: 'home'
  •   },
  •    components: {
  •      home: Home,
  •      kind: Kind,
  •      cart: Cart,
  •      user: User,
  •   },
  •    methods: {
  •      goPage (type) {
  •        this.type = type
  •     }
  •   }
  • })
  • </script>
  • </html>

案例:使用动态组件实现简易的步骤向导效果

  • <body>
  •  <div id="app">
  •    <button @click='change("step1")'>第一步</button>
  •    <button @click='change("step2")'>第二步</button>
  •    <button @click='change("step3")'>第三步</button>
  •    <keep-alive>
  •      <component :is="name"></component>
  •    </keep-alive>
  •  </div>
  • </body>
  • <script src="lib/vue.js"></script>
  • <script>
  •  var step1 = {
  •    template: '<div>这是第一步的操作</div>'
  • }
  •  var step2 = {
  •    template: '<div>这是第二步的操作</div>'
  • }
  •  var step3 = {
  •    template: '<div>这是第三步的操作</div>'
  • }
  •  var vm = new Vue({
  •    el: "#app",
  •    data: {
  •      name: "step2",
  •   },
  •    components: {
  •      step1,
  •      step2,
  •      step3
  •   },
  •    methods: {
  •      change:function(name){
  •        this.name = name
  •     }
  •   }
  • })
  • </script>

1.5 组件插槽

组件的最大特性就是 重用 ,而用好插槽能大大提高组件的可重用能力。

插槽的作用:父组件向子组件传递内容。

通俗的来讲,插槽无非就是在 子组件 中挖个坑,坑里面放什么东西由 父组件 决定。

插槽类型有:

  • 单个(匿名)插槽
  • 具名插槽
  • 作用域插槽
1.5.1 匿名插槽

匿名插槽一般就是使用单个插槽

  • <!DOCTYPE html>
  • <html lang="en">
  • <head>
  •  <meta charset="UTF-8">
  •  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  •  <title>06 动态组件钩子</title>
  • </head>
  • <body>
  •  <div id="app">
  •    <!-- 默认情况下,调用组件时,直接写到内部的内容是不会显示的 -->
  •    <!-- 如果想要显示,就在定义组件模版时,添加 slot 标签 -->
  •    <!-- 插槽:内容分发 -->
  •    <!-- 组件内部的代码显示还是不显示,在哪里显示,如何显示,这就是内容分发所干的活 -->
  •    <my-header>
  •      <ul>
  •        <li>logo</li>
  •        <li>搜索</li>
  •        <li>我的</li>
  •      </ul>
  •    </my-header>
  •    <my-header>
  •      <ul>
  •        <li>返回</li>
  •        <li>标题</li>
  •        <li></li>
  •      </ul>
  •    </my-header>
  •  </div>
  • </body>
  • <template id="header">
  •  <header>
  •    <slot></slot>
  •    <hr />
  •    <slot></slot>
  •  </header>
  • </template>
  • <script src="lib/vue.js"></script>
  • <script>
  •  const Header = {
  •    template: '#header'
  • }
  •  new Vue({
  •    el: '#app',
  •    components: {
  •      MyHeader: Header
  •   }
  • })
  • </script>
  • </html>

注意:子组件的 slot 标签中允许书写内容,当父组件不往子组件传递内容时, slot 中的内容才会被展示出来。

1.5.2 具名插槽

slot 元素可以用一个特殊的特性 name 来进一步配置如何分发内容。多个插槽可以有不同的名字,具名插槽将匹配内容片段中有对应 slot 特性的元素。

上中下 形式网页布局示例代码

  • <!DOCTYPE html>
  • <html lang="en">
  • <head>
  •  <meta charset="UTF-8">
  •  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  •  <title>06 动态组件钩子</title>
  • </head>
  • <body>
  •  <div id="app">
  •    <!-- 默认情况下,调用组件时,直接写到内部的内容是不会显示的 -->
  •    <!-- 如果想要显示,就在定义组件模版时,添加 slot 标签 -->
  •    <!-- 插槽:内容分发 -->
  •    <!-- 组件内部的代码显示还是不显示,在哪里显示,如何显示,这就是内容分发所干的活 -->
  •    <!-- 具名插槽:调用组件时,有多个代码需要显示到不同的位置
  •      定义模版添加slot 并配有 name 属性,调用组件时添加 slot属性指向之前的name的值
  •    -->
  •    <my-header>
  •      <div slot="left">logo</div>
  •      <div>搜索</div>
  •      <div slot="right">我的</div>
  •    </my-header>
  •    <my-header>
  •      <div slot="left">返回</div>
  •      <div>标题</div>
  •      <div slot="right"></div>
  •    </my-header>
  •  </div>
  • </body>
  • <template id="header">
  •  <header>
  •    <slot name="left"></slot>
  •    <!-- 默认的name属性为 default -->
  •    <slot></slot>
  •    <slot name="right"></slot>
  •  </header>
  • </template>
  • <script src="lib/vue.js"></script>
  • <script>
  •  const Header = {
  •    template: '#header'
  • }
  •  new Vue({
  •    el: '#app',
  •    components: {
  •      MyHeader: Header
  •   }
  • })
  • </script>
  • </html>

具名插槽存在的意义就是为了解决在单个页面中同时使用多个插槽。

1.5.3 作用域插槽 了解

应用场景:父组件对子组件的内容进行加工处理

作用域插槽是一种特殊类型的插槽,作用域插槽会绑定了一套数据,父组件可以拿这些数据来用,于是,情况就变成了这样:样式父组件说了算,但父组件中内容可以显示子组件插槽绑定的数据。

自 2.6.0 起有所更新。已废弃的使用 slot-scope attribute 的语法在这里

  • <!DOCTYPE html>
  • <html lang="en">
  • <head>
  •  <meta charset="UTF-8">
  •  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  •  <title>10 作用域插槽</title>
  • </head>
  • <body>
  •  <div id="app">
  •    <my-header>
  •      <div slot-scope="props">
  •        <h1>1111</h1>
  •       {{ props.test }}
  •      </div>
  •    </my-header>
  •  </div>
  • </body>
  • <template id="header">
  •  <header>
  •    <slot test = "测试"></slot>
  •  </header>
  • </template>
  • <script src="lib/vue.js"></script>
  • <script>
  •  const Header = {
  •    template: '#header'
  • }
  •  new Vue({
  •    el: '#app',
  •    components: {
  •      MyHeader: Header
  •   }
  • })
  • </script>
  • </html>
1.5.4 v-slot指令

https://cn.vuejs.org/v2/api/#v-slot

定义组件

挖个坑 <slot></slot>,如果要使用具名插槽<slot name="test"></slot>

调用组件时<template v-slot></template>或者 <template v-slot="test"></template>

  • <!DOCTYPE html>
  • <html lang="en">
  • <head>
  •  <meta charset="UTF-8">
  •  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  •  <title>11 v-slot</title>
  • </head>
  • <body>
  •  <div id="app">
  •    <my-header>
  •      <!-- <div slot="left">logo</div>
  •      <div>搜索</div>
  •      <div slot="right">我的</div> -->
  •      <template v-slot:left>
  •        <div>logo</div>
  •      </template>
  •      <div>搜索</div>
  •      <template v-slot:right>
  •        <div>我的</div>
  •      </template>
  •    </my-header>
  •  </div>
  • </body>
  • <template id="header">
  •  <header>
  •    <slot name="left"></slot>
  •    <!-- 默认的name属性为 default -->
  •    <slot></slot>
  •    <slot name="right"></slot>
  •  </header>
  • </template>
  • <script src="lib/vue.js"></script>
  • <script>
  •  const Header = {
  •    template: '#header'
  • }
  •  new Vue({
  •    el: '#app',
  •    components: {
  •      MyHeader: Header
  •   }
  • })
  • </script>
  • </html>
CDSY,CDSY.XYZ
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐