Vue笔记八——关于组件不可不知的知识!

组件化的实现和使用步骤

什么是组件化?

  • 人面对复杂问题的处理方式:

    • 任何一个人处理信息的逻辑能力都是有限的。
    • 所以,当面对一个非常复杂的问题时,我们不太可能一次性搞定一大堆内容。
    • 但是,我们人有一种天生的能力,拆分成很多个可以处理的小问题,再将其放在整体当中,你会发现问题也会迎刃而解。
  • 组件化也是类似的思想:

    • 如果我们将一个页面中所有的处理逻辑全部放在一起,处理起来就会变得非常复杂,而且不利于后续的管理以及扩展。
    • 但如果,我们将一个页面拆分成一个个小的功能块,每个功能块完成属于自己这部分独立的功能,那么,之后整个页面的管理和维护就会变得非常容易了。

Vue的组件化思想

  • 组件化是Vue.js中的重要思想
    • 它提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用。
    • 任何的应用都会被抽象成一颗组件数。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PnlLl4Ru-1609768401766)(/Users/mac/Desktop/前端学习笔记/vue/vue笔记八/1.png)]

  • 例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。

  • 组件化思想的应用

    • 有了组件化的思想,我们在之后的开发中就要充分的利用它。
    • 尽可能的将页面拆分成一个个小的、可复用的组件。
    • 这样让我们的代码更加方便组织和管理,并且扩展性也很强。

注册组件的基本步骤

  • 组件的使用分成三个步骤
    • 调用Vue.extend()方法创建组件构造器
    • 调用Vue.component()方法注册组件
    • 在Vue实例的作用范围内使用组件
<!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.使用组件 -->
    <my-cpn></my-cpn>
    <my-cpn></my-cpn>
    <my-cpn></my-cpn>
  </div>

  <script src="../js/vue.js"></script>
  <script>

    // 1.创建组件构造器对象
    const cpnConstructor = Vue.extend({
    
    
      template: 
        `
          <div>
            <h2>我是标题</h2>
            <p>我是内容,哈哈哈哈哈</p>
            <p>我是内容,嘿嘿嘿嘿嘿</p>
          </div>
        `
    });
    // 2.注册组件
    Vue.component('my-cpn', cpnConstructor);


    const app = new Vue({
    
    
      el: '#app',
      data: {
    
    

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t09Jc4LZ-1609768401770)(/Users/mac/Desktop/前端学习笔记/vue/vue笔记八/2.jpg)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KANDXa1J-1609768401775)(/Users/mac/Desktop/前端学习笔记/vue/vue笔记八/3.jpg)]

注册组件步骤解析

  • 这里的步骤都代表什么含义呢?
  • Vue.extend()
    • 调用Vue.extend()创建的是一个组件的构造器。
    • 通常在创建组件构造器时,传入template代表我们自定义组件的模板。
  • Vue.component()
    • 调用Vue.compoment()是将刚才的组件构造器注册为一个组件,并且给它起一个组件的标签名称。
    • 所需要传递两个参数:1、注册组件的标签名。2、组件构造器。
  • 组件必须挂载在某个Vue实例下,否则不会生效,如图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y6fLFHQ3-1609768401785)(/Users/mac/Desktop/前端学习笔记/vue/vue笔记八/4.jpg)]

全局组件和局部组件

首先,我们上面写的组件就是全局组件,可以在不同的Vue实例中使用,下面来说一下局部组件

<!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.使用组件 -->
    <cpn></cpn>
    <cpn></cpn>
    <cpn></cpn>
  </div>

  <div id="app2">
    <cpn></cpn>
    <cpn></cpn>
    <cpn></cpn>
  </div>

  <script src="../js/vue.js"></script>
  <script>

    // 1.创建组件构造器对象
    const cpnConstructor = Vue.extend({
    
    
      template: 
        `
          <div>
            <h2>我是标题</h2>
            <p>我是内容,哈哈哈哈哈</p>
            <p>我是内容,嘿嘿嘿嘿嘿</p>
          </div>
        `
    });
    // 2.注册组件(全局组件,意味着可以在多个Vue的实例下面使用)
    Vue.component('my-cpn', cpnConstructor);


    const app = new Vue({
    
    
      el: '#app',
      data: {
    
    

      },
      components: {
    
    
        // my-cpn使用组件时的标签名
        cpn: cpnConstructor,
      }
    });
    const app2 = new Vue({
    
    
      el: '#app2',
      data: {
    
    

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tur42Aib-1609768401789)(/Users/mac/Desktop/前端学习笔记/vue/vue笔记八/5.jpg)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h4sMsJuy-1609768401790)(/Users/mac/Desktop/前端学习笔记/vue/vue笔记八/6.jpg)]

父组件和子组件

  • 在前面我们看到了组件树:
    • 组件和组件之间存在层级关系。
    • 而其中一种非常重要的关系就是父子组件的关系。
  • 父子组件的错误用法:以子标签的形式在Vue实例中使用。
    • 因为当子组件注册到父组件的components时,Vue会编译好父组件的模块。
    • 该模块的内容已经决定了父组件将要渲染的HTML(相当于父组件中已经有了子组件)

看如下案例:

<!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">
    <cpn2></cpn2>
  </div>

  <script src="../js/vue.js"></script>
  <script>

    // 创建组件构造函数(子组件)
    const cpnConstructor1 = Vue.extend({
    
    
      template:`
        <div>
          <h2>我是子组件标题</h2>  
          <p>子组件子组件子组件</p>
        </div>
      `
    });

    // 创建组件构造函数(父组件)
    const cpnConstructor2 = Vue.extend({
    
    
      template:`
        <div>
          <h2>我是父组件标题</h2>  
          <p>父组件父组件父组件</p>
          <cpn1></cpn1>
        </div>
      `,
      components: {
    
    
        cpn1: cpnConstructor1,
      }
    });

    const app = new Vue({
    
    
      el: '#app',
      data: {
    
    

      },
      components: {
    
    
        cpn2: cpnConstructor2,
      }
    });

  </script>
</body>
</html>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qyp5XZjc-1609768401792)(/Users/mac/Desktop/前端学习笔记/vue/vue笔记八/7.jpg)]

我们在父组件的模板中注册并使用而子组件,并且在vue挂载中注册了父组件,所以可以使用父组件,但是没有在vue挂载中注册子组件,所以无法使用子组件。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AN1RhVjn-1609768401794)(/Users/mac/Desktop/前端学习笔记/vue/vue笔记八/8.jpg)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YO4rI8IL-1609768401797)(/Users/mac/Desktop/前端学习笔记/vue/vue笔记八/9.jpg)]

语法糖注册组件

语法糖注册全局组件

Vue.component('my-cpn', {
    
    
  template: `
      <div>
        <h2>我是标题</h2>
        <p>我是内容,哈哈哈哈哈</p>
        <p>我是内容,嘿嘿嘿嘿嘿</p>
      </div>
    `
});

语法糖注册局部组件

const app = new Vue({
    
    
  el: '#app',
  data: {
    
    

  },
  components: {
    
    
    'cpn2': {
    
    
      template:`
      <div>
        <h2>我是标题</h2>
        <p>我是内容,哈哈哈哈哈</p>
        <p>我是内容,嘿嘿嘿嘿嘿</p>
      </div>
      `
    }
  }
});

组件模板的分离

  • 刚才,我们通过语法糖简化了Vue组件的注册过程,另外还有一个地方的写法比较麻烦,就是template模块写法。
  • 如果我们能将其中的HTML分离出来写,然后挂载到对应的组件上,必然结构会变得非常清晰。
  • Vue提供两种方案来定义HTML模板内容:
    • 使用<script>标签
    • 使用<template>标签
<!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">
    <cpn></cpn>
  </div>

  <!-- 1.使用script标签,注意type="text/x-template" -->
  <!-- <script type="text/x-template" id="cpn">
    <div>
      <h2>我是标题</h2>
      <p>我是内容,哈哈哈</p>
    </div>
  </script> -->

  <!-- 2.使用template标签 -->
  <template id="cpn">
    <div>
      <h2>我是标题</h2>
      <p>我是内容,哈哈哈</p>
    </div>
  </template>


  <script src="../js/vue.js"></script>
  <script>

    // 注册一个全局组件
    Vue.component('cpn', {
    
    
      template: '#cpn'
    });

    const app = new Vue({
    
    
      el: '#app',
      data: {
    
    

      },
      components: {
    
    

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

组件可以访问Vue实例数据么?

  • 组件是一个单独功能模块的封装:
    • 这个模块由属于自己的HTML模板,也应该有属于自己的数据data。
  • 组件中的数据时保存在哪里的呢?顶层的Vue实例中么?
    • 我们经过测试,组件中不能直接访问Vue实例中的data。
    • 而且即使可以访问,如果所有数据都放在Vue实例中,Vue实例就会变得非常臃肿。
    • 结论:Vue组件应该有自己保存数据的地方。

组件数据的存放

  • 组件自己的数据存放在哪里?
    • 组件对象也有一个data属性(也可以有methods等属性,下面我们有用到)
    • 只是这个data属性必须是一个函数
    • 而且这个函数返回一个对象,对象内部保存着数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nSzenXmM-1609768401799)(/Users/mac/Desktop/前端学习笔记/vue/vue笔记八/10.jpg)]

父子组件的通信

  • 在前面将父子组件的时候,我们提到子组件是不能引用父组件或者Vue实例的数据的。

  • 但是在开发中,往往一些数据确实需要从上层传递到下层

    • 比如在一个页面中,我们从服务器请求到了很多的数据。
    • 其中一部分数据,并非是我们整个页面的大组件来展示的,而是需要下面的子组件进行展示。
    • 这个时候,并不会让子组件再一次发送一个网站请求,而是直接让大组件(父组件)将数据传递给小组件(子组件)
  • 如何进行父子组件间的通信呢?Vue官方提到:

    • 通过props向子组件传递
    • 通过事件向父组件发送消息
  • 下面的代码中,我们直接将Vue实例当做父组件,并且其中包含子组件来简化代码。

  • 在真实开发中,Vue实例和子组件的通信父组件和子组件的通信过程是一样的。

props基本用法(父传子)

  • 在组件中,使用选项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>08-组件通信-父组件向子组件传递数据</title>
</head>
<body>
  <div id="app">
    <cpn :cmovies="movies" :cmessage="message"></cpn>
  </div>

  <template id="cpn">
    <div>
      <h2>{
    
    {
    
    cmessage}}</h2>
      <p>{
    
    {
    
    cmovies}}</p>
    </div>
  </template>

  <script src="../js/vue.js"></script>
  <script>

    // 父传子:props
    const cpn = {
    
    
      template: '#cpn',
      data() {
    
    
        return {
    
    

        }
      },
      props: ['cmovies', 'cmessage'],
      methods: {
    
    

      },
    }

    const app = new Vue({
    
    
      el: '#app',
      data: {
    
    
        message: '我是阿牛',
        movies: ['海王', '海贼王', '海尔兄弟'],
      },
      components: {
    
    
        cpn
      }
    });
  </script>
</body>
</html>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y3HuOwgG-1609768401801)(/Users/mac/Desktop/前端学习笔记/vue/vue笔记八/11.jpg)]

  • 在前面,我们的props选项是使用一个数组。
  • 我们说过,除了数组之外,我们也可以使用对象,当需要对props进行类型验证时,就需要对象写法了。
  • 验证都支持哪些数据类型呢?
    • String
    • Number
    • Boolean
    • Array
    • Object
    • Date
    • Function
    • Symbol
  • 当我们又自定义构造函数时,验证也支持自定义的类型。
props: {
    
    
  cmovies: {
    
    
    type: Array,
    default() {
    
    
      return []
    },
  },
  cmessage: {
    
    
    type: String,
    default: '12345',
  }
}

自定义事件(子传父)

  • props用于父组件向子组件传递数据,还有一种比较常见的是子组件传递数据或事件到父组件中。
  • 我们应该如何处理呢?这个时候,我们需要使用自定义事件来完成。
  • 什么时候需要自定义事件呢?
    • 当子组件需要向父组件传递参数时,我们就要用到自定义事件了。
    • 我们之前学习的v-on不仅仅可以用于监听DOM事件,也可以用于组件间的自定义事件。
  • 自定义事件流程
    • 在子组件中,通过$emit()来触发事件。
    • 在父组件中,通过v-on来监听子组件。
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title><!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">
    <cpn @item-click="cpnClick"></cpn>
  </div>

  <!-- 子组件模板 -->
  <template id="cpn">
    <div>
      <button v-for="item in categroies"
              @click="btnClick(item)">{
    
    {
    
    item.name}}</button>
    </div>
  </template>

  <script src="../js/vue.js"></script>
  <script>

    // 子组件
    const cpn = {
    
    
      template: '#cpn',
      data() {
    
    
        return {
    
    
          categroies: [
            {
    
    id: 'aaa', name: '热门推荐'},
            {
    
    id: 'aaa', name: '手机数码'},
            {
    
    id: 'aaa', name: '家用家电'},
            {
    
    id: 'aaa', name: '电脑办公'},
          ],
        }
      },
      methods: {
    
    
          btnClick(item) {
    
    
            // 发射事件
            this.$emit('item-click', item);
          }
        }       
      }
    // 父组件
    const app = new Vue({
    
    
      el: '#app',
      data: {
    
    
        message: '我是阿牛',
      },
      components: {
    
    
        cpn
      },
      methods: {
    
    
        cpnClick(item) {
    
    
          console.log(item.name);
        }
      }
    });
  </script>
</body>
</html>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H52qQEPN-1609768401802)(/Users/mac/Desktop/前端学习笔记/vue/vue笔记八/12.jpg)]

这样我们点击按钮,就会触发子组件传递给父组件的item-click事件,父组件执行方法cpnClick,将从子组件一同传来的参数item传入cpnClick方法,并执行该方法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aNDpfygb-1609768401806)(/Users/mac/Desktop/前端学习笔记/vue/vue笔记八/13.gif)]

父子组件传值案例

<!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">
    <cpn :number1="num1" 
          :number2="num2"
          @num1change="num1change"
          @num2change="num2change"
           ></cpn>
  </div>

  <!-- 子组件模板 -->
  <template id="cpn">
    <div>
      <h2>props:{
   
   {number1}}</h2>
      <h2>data:{
   
   {dnumber1}}</h2>
      <!-- <input type="text" v-model="dnumber1"> -->
      <input type="text" :value="dnumber1" @input="num1Input">
      <h2>props:{
   
   {number2}}</h2>
      <h2>data:{
   
   {dnumber2}}</h2>
      <input type="text" :value="dnumber2" @input="num2Input">
    </div>
  </template>

  <script src="../js/vue.js"></script>
  <script>

    // 子组件
    const cpn = {
     
     
      template: '#cpn',
      props: {
     
     
        number1: Number,
        number2: Number,
      },
      data() {
     
     
        return {
     
     
          dnumber1: this.number1,
          dnumber2: this.number2,
        }
      },
      methods: {
     
     
        num1Input(event) {
     
     
          // 1. 将input中的value赋值到dnumber中
          this.dnumber1 = event.target.value;
          // 2. 为了让父组件可以修改值,发出一个事件
          this.$emit('num1change', this.dnumber1);
          // 3. 同时修改dnumber2的值
          this.dnumber2 = this.dnumber1 * 100;
          this.$emit('num2change', this.dnumber2);
        },
        num2Input(event) {
     
     
          // 1.将input中的value赋值到dnumber2
          this.dnumber2 = event.target.value;
          // 2. 为了让父组件可以修改值,发出一个事件
          this.$emit('num2change', this.dnumber2);

          // 3. 同时修改dnumber1的值
          this.dnumber1 = this.dnumber2 / 100;
          this.$emit('num1change', this.dnumber1);
        }
      }
    }

    // 父组件
    const app = new Vue({
     
     
      el: '#app',
      data: {
     
     
        num1: 0,
        num2: 1
      },
      components: {
     
     
        cpn
      },
      methods: {
     
     
        num1change(value) {
     
     
          this.num1 = value * 1;
        },
        num2change(value) {
     
     
          this.num2 = value * 1;
        }
      }
    })
  </script>
</body>
</html>
  • 该案例结合了双向绑定,融汇贯通父子组件的传值,略显复杂。

  • 达到一个效果:下面的值num2是上面的值num1的100倍。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UEEel2Mp-1609768401807)(/Users/mac/Desktop/前端学习笔记/vue/vue笔记八/14.gif)]

父子组件的访问方式

  • 有时候我们需要父组件直接访问子组件,子组件直接访问父组件,或者是子组件访问跟组件。
    • 父组件访问子组件:使用$children$refs
    • 子组件访问父组件:使用$parent

$children的使用

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>11-组件访问-父访问子-children</title>
</head>
<body>
  <div id="app">
    <cpn></cpn>
    <cpn></cpn>
    <cpn></cpn>
    <button @click="btnClick">按钮</button>
  </div>


  <template id="cpn">
    <div>
      <h2>我是子组件</h2>
    </div>
  </template>

  <script src="../js/vue.js"></script>
  <script>

    const cpn = {
    
    
      template: '#cpn',
      data() {
    
    
        return {
    
    
          name: '我是子组件的name'
        }
      },
      methods: {
    
    
        showMessage() {
    
    
          console.log('showMessage');
        }
      }
    }

    const app = new Vue({
    
    
      el: '#app',
      data: {
    
    
      },
      components: {
    
    
        cpn
      },
      methods: {
    
    
        btnClick() {
    
    
          console.log(this.$children);
          for(let c of this.$children){
    
    
            console.log(c.name);
            c.showMessage();
          }
        }
      }
    });
  </script>
</body>
</html>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DbCWojVX-1609768401810)(/Users/mac/Desktop/前端学习笔记/vue/vue笔记八/15.jpg)]

$refs的使用

  • 上面我们使用$children获得子组件,当时使用这个方法在实际开发中比较少。因为想要获取某个特定的组件,就需要知道该组件在其父组件中的位置,也就是需要知道获得的数组的索引下标。
  • 而我们用的最多的是这个$refs
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>12-组件访问-父访问子-ref</title>
</head>
<body>
  <div id="app">
    <cpn></cpn>
    <cpn></cpn>
    <cpn ref="aaa"></cpn>
    <button @click="btnClick">按钮</button>
  </div>


  <template id="cpn">
    <div>
      <h2>我是子组件</h2>
    </div>
  </template>

  <script src="../js/vue.js"></script>
  <script>

    const cpn = {
    
    
      template: '#cpn',
      data() {
    
    
        return {
    
    
          name: '我是子组件的name'
        }
      },
      methods: {
    
    
        showMessage() {
    
    
          console.log('showMessage');
        }
      }
    }

    const app = new Vue({
    
    
      el: '#app',
      data: {
    
    
      },
      components: {
    
    
        cpn
      },
      methods: {
    
    
        btnClick() {
    
    
          console.log(this.$refs.aaa.name);
        }
      }
    });
  </script>
</body>
</html>
  • $refs获取一个对象,包含所有设置了ref属性(ref=aaa)的子组件,然后通过$refs.aaa就可以获得该子组件了。

$parent

  • 通过$parent可以访问父组件,但是在实际开发中使用较少。

$root

  • 通过$root可以访问根组件,也很少用。
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>13-组件访问-子访问父-parent</title>
</head>
<body>
  <div id="app">
    <cpn></cpn>
  </div>


  <template id="cpn">
    <div>
      <h2>我是cpn</h2>
      <ccpn></ccpn>
    </div>
  </template>

  <template id="ccpn">
    <div>
      <h2>我是ccpn</h2>
      <button @click="getParent">获得父组件</button>
      <button @click="getRoot">获得根组件</button>
    </div>
  </template>

  <script src="../js/vue.js"></script>
  <script>

    const ccpn = {
    
    
      template: '#ccpn',
      methods: {
    
    
        getParent() {
    
    
          console.log(this.$parent);
        },
        getRoot() {
    
    
          console.log(this.$root);
        }
      }
    }

    const cpn = {
    
    
      template: '#cpn',
      components: {
    
    
        ccpn
      }
    }

    const app = new Vue({
    
    
      el: '#app',
      components: {
    
    
        cpn
      }
    });
  </script>
</body>
</html>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vTmcLEKA-1609768401813)(/Users/mac/Desktop/前端学习笔记/vue/vue笔记八/16.gif)]

回顾

Vue笔记一——Vue安装与体验
Vue笔记二——Vue声明周期与模板语法
Vue笔记三——计算属性(computed)
Vue笔记四——事件监听的使用
Vue笔记五——条件判断与循环遍历
Vue笔记六——书籍购物车案例
Vue笔记七——v-model表单输入绑定详细介绍

猜你喜欢

转载自blog.csdn.net/weixin_46351593/article/details/112206734