從零開始學 Web 之 Vue.js(六)Vue的組件

你們好,這裏是「 從零開始學 Web 系列教程 」,並在下列地址同步更新......javascript

  • github:https://github.com/Daotin/Web
  • 微信公衆號:Web前端之巔
  • 博客園:http://www.cnblogs.com/lvonve/
  • CSDN:https://blog.csdn.net/lvonve/

在這裏我會從 Web 前端零基礎開始,一步步學習 Web 相關的知識點,期間也會分享一些好玩的項目。如今就讓咱們一塊兒進入 Web 前端學習的冒險之旅吧!css

1、Vue組件

什麼是組件: 組件的出現,就是爲了拆分 Vue 實例的代碼量的,可以讓咱們以不一樣的組件,來劃分不一樣的功能模塊,未來咱們須要什麼樣的功能,就能夠去調用對應的組件便可;html

組件化和模塊化的不一樣:前端

  • 模塊化: 是從代碼邏輯的角度進行劃分的;方便代碼分層開發,保證每一個功能模塊的職能單一;
  • 組件化: 是從UI界面的角度進行劃分的;前端的組件化,方便UI組件的重用;

2、定義組件

一、定義全局組件

定義全局組件有三種方式:vue

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

// 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>

注意:git

使用 Vue.component 定義全局組件的時候,組件名稱使用了 駝峯命名(如myLogin),則在引用組件的時候,須要把 大寫的駝峯改成小寫的字母,同時在兩個單詞以前,使用 - 連接(<my-login></my-login>);若是不使用駝峯,則直接拿名稱來使用便可;github

固然,上面兩步能夠合成一個步驟完成:微信

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

二、直接使用 Vue.component 方法:app

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

注意:不管是哪一種方式建立出來的組件,組件的 template 屬性指向的模板內容,必須有且只能有惟一的一個根元素,不然會報錯。

三、將模板字符串,定義到 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>

注意:

一、template: '#tmp1' 是定義模板標籤的 id ,# 別忘寫了。

二、被控制的 #box 外面,使用 template 標籤;

三、 template 標籤裏面,仍是聽從只能有惟一的一個根元素的原則。

二、定義私有組件

定義私有組件,就是再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>

三、組件的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>

3、組件切換

咱們在登陸註冊一個網站的時候,常常看到兩個按鈕,一個登陸,一個註冊,若是你沒有帳號的話,須要先註冊才能登陸。咱們在點擊登陸和註冊的時候,網頁會相應的切換,登陸頁面就是登錄組件,註冊頁面就是註冊組件,那麼點擊登陸和註冊,如何實現組件的切換呢?

一、方式一

使用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,因此只能用於兩個組件間 的切換,當大於兩個組件的切換就不行了。

二、方式二

使用 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 {
      width: 200px;
      height: 200px;
      background-color: red;
    }

    .registerDiv {
      width: 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":能夠設置切換組件的模式爲先退出再進入。

4、組件傳值

一、父組件向子組件傳值

咱們先經過一個例子看看子組件可不能夠直接訪問父組件的數據:

<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,評論人,內容做爲子組件,把列表做爲父組件,而後把添加的數據放到父組件列表上,因爲要獲取到父組件列表的數據,因此必然涉及到父組件向子組件傳值的過程。這裏還經過子組件方法參數來保存父組件的數據到子組件的數據中。

二、父組件向子組件傳方法

既然父組件能夠向子組件傳遞數據,那麼也能夠向子組件傳遞方法。

<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>

一、@parentfunc="show" 綁定父組件的show方法。

二、<input type="button" value="調用父組件方法" @click="sonClick"> 點擊按鈕調用父組件的show方法

三、在 子組件的 sonClick 方法中使用 this.$emit("parentfunc"); 來調用父組件的show方法

四、父組件的show方法也能夠傳參,在調用的時候,實參從 this.$emit 的第二個參數開始傳入。

五、若是 this.$emit 的第二個參數傳的是子組件的data數據,那麼父組件的方法就能夠得到子組件的數據,這也是把子組件的數據傳遞給父組件的方式。

三、使用 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>

總結:

一、ref 屬性不只能夠獲取DOM元素,也能夠獲取組件(不管全局仍是私有組件)元素。

二、獲取到組件元素後,就能夠獲取組件元素的data數據和methods方法。

三、獲取到組件中的方法後,能夠傳入VM的data數據,就能夠把VM的data數據傳入組件中。

相關文章
相關標籤/搜索