zoukankan      html  css  js  c++  java
  • 从零开始学 Web 之 Vue.js(六)Vue的组件

    大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新......

    在这里我会从 Web 前端零基础开始,一步步学习 Web 相关的知识点,期间也会分享一些好玩的项目。现在就让我们一起进入 Web 前端学习的冒险之旅吧!

    一、Vue组件

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

    组件化和模块化的不同:

    • 模块化: 是从代码逻辑的角度进行划分的;方便代码分层开发,保证每个功能模块的职能单一;
    • 组件化: 是从UI界面的角度进行划分的;前端的组件化,方便UI组件的重用;

    二、定义组件

    1、定义全局组件

    定义全局组件有三种方式:

    1、使用 Vue.extend 配合 Vue.component 方法:

    // 1.使用 Vue.extend 来创建全局的Vue组件
    var login = Vue.extend({
      // 通过 template 属性,指定了组件要展示的HTML结构
      template: '<h1>登录</h1>'
    });
    
    // 2.使用 Vue.component('组件的名称', 创建出来的组件模板对象) 
    Vue.component('login', login);
    
    // 3.使用组件
    <div id="app">
    	<!-- 如果要使用组件,直接,把组件的名称,以 HTML 标签的形式,引入到页面中即可 -->
    	<login></login>
    </div>

    注意:

    使用 Vue.component 定义全局组件的时候,组件名称使用了 驼峰命名(如myLogin),则在引用组件的时候,需要把 大写的驼峰改为小写的字母,同时在两个单词之前,使用 - 链接(<my-login></my-login>);如果不使用驼峰,则直接拿名称来使用即可;

    当然,上面两步可以合成一个步骤完成:

    Vue.component('login', Vue.extend({
      template: '<h1>登录</h1>'
    }));

    2、直接使用 Vue.component 方法:

    Vue.component('login', {
      template: '<div><h3>注册</h3><span>123</span></div>'
    });

    注意:不论是哪种方式创建出来的组件,组件的 template 属性指向的模板内容,必须有且只能有唯一的一个根元素,否则会报错。

    3、将模板字符串,定义到 template 标签中:

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <title>Document</title>
      <script src="./lib/vue-2.4.0.js"></script>
    </head>
    
    <body>
      <div id="box">
        <!-- 3. 使用组件 -->
        <mycom></mycom>
      </div>
      <!-- 2.在 被控制的 #box 外面,使用 template 元素,定义组件的HTML模板结构  -->
      <template id="tmp1">
        <!-- 还是需要遵从template 模板内容,必须有且只能有唯一的一个根元素 -->
        <div>
          <h3>登录</h3>
          <p>p标签</p>
        </div>
      </template>
    
      <script>
        // 1.定义组件
        Vue.component('mycom', {
          template: '#tmp1'
        });
    
        var vm = new Vue({
          el: "#box",
          data: {},
          methods: {}
        });
      </script>
    </body>
    
    </html>

    注意:

    1、template: '#tmp1' 是定义模板标签的 id ,# 别忘写了。

    2、被控制的 #box 外面,使用 template 标签;

    3、 template 标签里面,还是遵从只能有唯一的一个根元素的原则。

    2、定义私有组件

    定义私有组件,就是再VM实例中定义组件。

    如下,box中可以使用,box2不可以使用。

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <title>Document</title>
      <script src="./lib/vue-2.4.0.js"></script>
    </head>
    
    <body>
      <div id="box">
        <mycom></mycom>
      </div>
    
      <div id="box2">
        <mycom></mycom>
      </div>
    
      <template id="temp">
        <h3>自定义私有属性</h3>
      </template>
    
      <script>
        var vm = new Vue({
          el: "#box",
          data: {},
          methods: {},
          // 定义私有组件
          components: {
            mycom: {
              template: '#temp'
            }
          }
        });
        var vm2 = new Vue({
          el: "#box2",
          data: {},
          methods: {}
        });
      </script>
    </body>
    
    </html>

    3、组件的data和methods属性

    组件中也可以有自己的data和methods属性,可以传入template中使用。

    特点:

    • data属性为一个匿名函数,其返回值为一个对象。
    • data 函数返回值为一个对象(最好是新开辟的对象,否则如果多次引用组件,不是新开辟的对象给的话,对象是同一份,而我们需要每一个组件有自己的对象),对象中可以放入数据。
    • 组件中 的data和methods,使用方式,和实例中的 data 和methods使用方式完全一样
    <div id="box2">
      <login></login>
    </div>
    
    <template id="temp2">
      <div>
        <input type="button" value="按钮" @click="myclick">
        <h3>自定义私有属性</h3>
        <p> {{msg}} </p>
      </div>
    </template>
    
    <script>
      Vue.component('login', {
        template: '#temp2',
        data: function () {
          return {
            msg: '这是组件中的data'
          }
        },
        methods: {
          myclick() {
            console.log("点击按钮");
          }
      }
      });
    </script>

    三、组件切换

    我们在登录注册一个网站的时候,经常看到两个按钮,一个登录,一个注册,如果你没有账号的话,需要先注册才能登录。我们在点击登录和注册的时候,网页会相应的切换,登录页面就是登陆组件,注册页面就是注册组件,那么点击登录和注册,如何实现组件的切换呢?

    1、方式一

    使用flag标识符结合v-ifv-else切换组件

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <title>Document</title>
      <script src="./lib/vue-2.4.0.js"></script>
    </head>
    
    <body>
      <div id="box">
        <!-- 给a注册点击事件,切换flag状态 -->
        <a href="javascript:;" @click.prevent="flag=true">登录</a>
        <a href="javascript:;" @click.prevent="flag=false">注册</a>
        <!-- 使用v-if v-else切换组件 -->
        <login v-if="flag">
        </login>
        <register v-else="flag">
        </register>
      </div>
    
      <script>
        Vue.component('login', {
          template: '<h3>登录组件</h3>'
        });
        Vue.component('register', {
          template: '<h3>注册组件</h3>'
        });
    
        var vm = new Vue({
          el: "#box",
          data: {
            flag: true
          },
          methods: {}
        });
      </script>
    </body>
    
    </html>

    缺陷:由于flag的值只有true和false,所以只能用于两个组件间 的切换,当大于两个组件的切换就不行了。

    2、方式二

    使用 component元素的:is属性来切换不同的子组件

    使用 <component :is="componentId"></component> 来指定要切换的组件。

    componentId:为需要显示的组件名称,为一个字符串,可以使用变量指定。

    componentId: 'login' // 默认显示登录组件。

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <title>Document</title>
      <script src="./lib/vue-2.4.0.js"></script>
    </head>
    
    <body>
      <div id="box">
        <!-- 给a注册点击事件,切换flag状态 -->
        <a href="javascript:;" @click.prevent="componentId='login'">登录</a>
        <a href="javascript:;" @click.prevent="componentId='register'">注册</a>
        <component :is="componentId"></component>
      </div>
    
      <script>
        Vue.component('login', {
          template: '<h3>登录组件</h3>'
        });
        Vue.component('register', {
          template: '<h3>注册组件</h3>'
        });
    
        var vm = new Vue({
          el: "#box",
          data: {
            componentId: 'login'   // 默认显示登录
          },
          methods: {}
        });
      </script>
    </body>
    
    </html>

    为组件切换添加过渡:

    很简单,只需要用 transition 将 component 包裹起来即可。

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

    示例:

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <title>Document</title>
      <script src="./lib/vue-2.4.0.js"></script>
      <link rel="stylesheet" href="./lib/animate.css">
    
      <style>
        .loginDiv {
           200px;
          height: 200px;
          background-color: red;
        }
    
        .registerDiv {
           200px;
          height: 200px;
          background-color: blue;
        }
      </style>
    </head>
    
    <body>
      <div id="box">
        <!-- 给a注册点击事件,切换flag状态 -->
        <a href="javascript:;" @click.prevent="componentId='login'">登录</a>
        <a href="javascript:;" @click.prevent="componentId='register'">注册</a>
        <transition mode="out-in" enter-active-class="animated bounceInRight" leave-active-class="animated bounceOutRight">
          <component :is="componentId"></component>
        </transition>
      </div>
    
      <template id="login">
        <div class="loginDiv">
        </div>
      </template>
    
      <template id="register">
        <div class="registerDiv">
        </div>
      </template>
    
      <script>
        Vue.component('login', {
          template: '#login'
        });
        Vue.component('register', {
          template: '#register'
        });
    
        var vm = new Vue({
          el: "#box",
          data: {
            componentId: 'login'
          },
          methods: {}
        });
      </script>
    </body>
    
    </html>

    mode="out-in":可以设置切换组件的模式为先退出再进入。

    四、组件传值

    1、父组件向子组件传值

    我们先通过一个例子看看子组件可不可以直接访问父组件的数据:

    <body>
      <div id="box">
        <mycom></mycom>
      </div>
    
      <template id="temp">
        <h3>子组件 --- {{msg}}</h3>
      </template>
    
      <script>
        var vm = new Vue({
          el: "#box",
          data: {
            msg: '父组件的msg'
          },
          methods: {},
          components: {
            mycom: {
              template: '#temp'
            }
          }
        });
      </script>
    </body>

    由于 components 定义的是私有组件,我们直接在子组件中调用父组件的msg会报错。

    那么,怎么让子组件使用父组件的数据呢?

    父组件可以在引用子组件的时候, 通过 属性绑定(v-bind:) 的形式, 把需要传递给子组件的数据,以属性绑定的形式,传递到子组件内部,供子组件使用 。

    <body>
      <div id="box">
        <mycom v-bind:parentmsg="msg"></mycom>
      </div>
    
      <template id="temp">
        <h3>子组件 --- 父组件:{{parentmsg}}</h3>
      </template>
    
      <script>
        var vm = new Vue({
          el: "#box",
          data: {
            msg: '父组件的msg'
          },
          methods: {},
          components: {
            mycom: {
              template: "#temp",
              // 对传递给子组件的数据进行声明,子组件才能使用 
              props: ['parentmsg']
            }
          }
        });
      </script>
    </body>

    注意:父组件绑定的属性名称不能有大写字母,否则不会显示,并且在命令行会有提示:

    组件data数据和props数据的区别:

    • data数据是子组件私有的,可读可写;
    • props数据是父组件传递给子组件的,只能读,不能写。

    案例:发表评论功能

    父组件为评论列表,子组件为ID,评论者,内容和按钮的集合,在输入ID,评论者等内容,然后点击添加的时候,需要首先获取子组件的list列表,然后再添加新的列表项到列表中。

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <title>Document</title>
      <script src="./lib/vue-2.4.0.js"></script>
    </head>
    
    <body>
      <div id="box">
        <mycom :plist="list"></mycom>
    
        <ul>
          <li v-for="item in list" :key="item.id">
            ID:{{item.id}} --- 内容:{{item.content}} --- 评论人:{{item.user}}
          </li>
        </ul>
      </div>
    
      <template id="tmp1">
        <div>
          <label>
            ID:
            <input type="text" v-model="id">
          </label>
          <br>
          <label>
            评论者:
            <input type="text" v-model="user">
          </label>
          <br>
          <label>
            内容:
            <textarea v-model="content"></textarea>
          </label>
          <br>
          <!-- 把父组件的数据作为子组件的函数参数传入 -->
          <input type="button" value="添加评论" @click="addContent(plist)">
        </div>
      </template>
    
      <script>
        var vm = new Vue({
          el: "#box",
          data: {
            list: [{
              id: Date.now(),
              user: 'user1',
              content: 'what'
            }, {
              id: Date.now(),
              user: 'user2',
              content: 'are'
            }]
          },
          methods: {},
          components: {
            mycom: {
              template: '#tmp1',
              data: function () {
                return {
                  id: '',
                  user: '',
                  content: '',
                }
              },
              methods: {
                addContent(plist) {
                  plist.unshift({
                    id: this.id,
                    user: this.user,
                    content: this.content
                  });
                }
              },
              props: ['plist']
            }
          }
        });
      </script>
    </body>
    
    </html>

    把添加ID,评论人,内容作为子组件,把列表作为父组件,然后把添加的数据放到父组件列表上,由于要获取到父组件列表的数据,所以必然涉及到父组件向子组件传值的过程。这里还通过子组件方法参数来保存父组件的数据到子组件的数据中。

    2、父组件向子组件传方法

    既然父组件可以向子组件传递数据,那么也可以向子组件传递方法。

    <body>
      <div id="box">
        <mycom v-bind:parentmsg="msg" @parentfunc="show"></mycom>
      </div>
    
      <template id="temp">
        <div>
          <input type="button" value="调用父组件方法" @click="sonClick">
          <h3>子组件 --- 父组件:{{parentmsg}}</h3>
        </div>
      </template>
    
      <script>
        var vm = new Vue({
          el: "#box",
          data: {
            msg: '父组件的msg'
          },
          methods: {
            show(data1, data2) {
              console.log("这是父组件的show方法" + data1 + data2);
            }
          },
          components: {
            mycom: {
              template: "#temp",
              // 对传递给子组件的数据进行声明,子组件才能使用 
              props: ['parentmsg'],
              methods: {
                sonClick() {
                  // 调用父组件的show方法
                  this.$emit("parentfunc", 111, 222);
                }
              }
            }
          }
        });
      </script>
    </body>

    1、@parentfunc="show" 绑定父组件的show方法。

    2、<input type="button" value="调用父组件方法" @click="sonClick"> 点击按钮调用父组件的show方法

    3、在 子组件的 sonClick 方法中使用 this.$emit("parentfunc"); 来调用父组件的show方法

    4、父组件的show方法也可以传参,在调用的时候,实参从 this.$emit 的第二个参数开始传入。

    5、如果 this.$emit 的第二个参数传的是子组件的data数据,那么父组件的方法就可以获得子组件的数据,这也是把子组件的数据传递给父组件的方式。

    3、使用 ref 获取DOM和组件的引用

    我们知道Vue不推荐直接获取DOM元素,那么在Vue里面怎么获取DOM及组件元素呢?

    我们呢可以在元素上使用 ref 属性来获取元素。

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <title>Document</title>
      <script src="./lib/vue-2.4.0.js"></script>
    </head>
    
    <body>
      <div id="box">
        <input type="button" value="获取元素" @click="getrefs" ref="mybtn">
        <h3 ref="myh3">这是H3</h3>
        <mycom ref="mycom"></mycom>
      </div>
    
      <template id="tmp1">
      </template>
    
      <script>
        // 定义组件
        Vue.component('mycom', {
          template: '#tmp1',
          data: function () {
            return {
              msg: '子组件的msg',
              pmsg: ''
            }
          },
          methods: {
            show(data) {
              console.log('调用子组件的show');
              this.pmsg = data;
              console.log(this.pmsg);
            },
    
          }
        });
    
        var vm = new Vue({
          el: "#box",
          data: {
            parentmsg: '父组件的msg'
          },
          methods: {
            getrefs() {
              console.log(this.$refs.myh3);
              console.log(this.$refs.mycom.msg);
              this.$refs.mycom.show(this.parentmsg);
            }
          }
        });
      </script>
    </body>
    
    </html>

    总结:

    1、ref 属性不仅可以获取DOM元素,也可以获取组件(无论全局还是私有组件)元素。

    2、获取到组件元素后,就可以获取组件元素的data数据和methods方法。

    3、获取到组件中的方法后,可以传入VM的data数据,就可以把VM的data数据传入组件中。

  • 相关阅读:
    学习Linux shell脚本中连接字符串的方法
    使用 ffmpeg 转换视频格式
    一点不懂到小白的linux系统运维经历分享
    linux利用scp远程上传下载文件/文件夹
    angular ui-select
    JavaScript sort()方法
    js性能优化
    layer弹出层
    JS复制对象
    某天修改了啥bat批处理
  • 原文地址:https://www.cnblogs.com/lvonve/p/14180361.html
Copyright © 2011-2022 走看看