vue學習筆記(六) ----- vue元件

千夏Chinatsu發表於2020-10-28

一、模組化與元件化

  • 模組化的定義

模組化在Node中是一個規範,定義一些模組的相關的規則,從程式碼角度上來說,方便做區別,如果不使用模組化,寫在js檔案中不利於後期維護和擴充套件,從程式碼的層面上就把相關的功能脫離出來,所以模組化從從程式碼的角度觸發,分析專案,把專案中一些功能型別的程式碼,單獨抽離為一個個的模組,那麼為了保證大家以相同的方式去封裝模組,於是我們就創造了CommentJS規範

  • 模組化的優點

在我們專案中,如果需要是實現相同的功能,就不需要再重寫,所以模組化從一定程度上提高我們的開發效率,有一些相關模組,直接呼叫就可以了,方便專案開發,和後期的維護與擴充套件

  • 元件化:

把頁面中樣式差不多的東西抽為單獨的小元件,把需要經常複用的東西封裝為一個單獨的,今後需要用的時候直接拿就可以,不用再重寫,從ui的角度觸發去考慮問題,把頁面中程式碼結構類似的區域抽離出來,封裝成一個單獨的小元件 ;前端的元件化,方便UI元件的重用;

  • 元件化的優點:

隨著專案規模的發展,我們手中的元件會越來越多,我們今後一個頁面的ui,幾乎都可以從手中拿現成的元件拼接出來,方便專案的開發和維護

二、建立全域性元件的方式

1. 建立全域性元件的方式一

  1. 先呼叫 Vue.extend()得到元件的建構函式
 var com1 = Vue.extend({
        template: '<h2>這是建立的第一個全域性元件</h2>' 
        // template 屬性,表示這個元件的 UI 程式碼解構
})
  1. 通過vue.component('元件的名稱',元件的建構函式)來註冊全域性元件
    Vue.component('mycom1', com1)
    //com1就是元件的建構函式

注意:
元件的名稱如果是駝峰命名,那麼引入的時候表名稱得加連字元 -
1.如果 Vue.component('myCom1','com1')
對應的元件標籤是
2. 如果是Vue.component('myCom1Test','com1')
對應元件標籤為:
3. 如果Vue.component('my-com1','com1')
對應元件標籤為:

  1. 把註冊好的元件名稱,以標籤的形式引入到vm例項區域的頁面中即可
<div id="app">
<!--    引入全域性的vue元件-->
    <mycom1></mycom1>
</div>

來吧展示:

在這裡插入圖片描述

2. 建立全域性元件的方式二

  1. 直接使用vue.component('元件的名稱','元件物件')
// Vue.component 的第二個引數,既接收 一個 元件的建構函式, 同時,也接受 一個物件
 Vue.component('mycom2', {
     template:'<h2>這是直接使用 Vue.component 建立出來的元件</h2>'
})
  1. 把註冊好的元件名稱,以標籤的形式引入到vm例項區域的頁面中即可
<div id="app">
    <mycom2></mycom2>
</div>

來吧展示:

在這裡插入圖片描述

注意:
1.template 屬性中,不能單獨放一段文字,必須用標籤包裹起來;
2. 如果在 template 屬性中,想要放多個元素了,那麼,在這些元素外,必須有唯一的一個根元素進行包裹;

Vue.component('mycom2', {
     template:'<div><p>嘿嘿嘿嘿嘿</p><h2>這是直接使用 Vue.component 建立出來的元件</h2><h1>哈哈哈哈</h1> </div>'
 })

在這裡插入圖片描述

3. 建立全域性元件的方式三

  1. template新增一個id選擇器
Vue.component('mycom3', {
        template: '#tpl'
})
  1. 定義一個 template 標籤元素
    使用 Vue 提供的 template 標籤,可以定義元件的UI模板解構
<div id="app">
   <mycom3></mycom3>
</div>
<template id="tpl">
    <h2>這是建立全域性元件的第三種方式</h2>
</template>

在這裡插入圖片描述

注意:
template標籤中裡面也必須有唯一的一個根元素進行包裹
也就是如果沒有根元素包裹,那麼下面程式碼是執行不出來了會報錯

<template id="tmpl">
        <h2>這是建立全域性元件的第三種方式</h2>
        <p>喲喲喲喲喲喲</p>
</template>

正確寫法:

<template id="tmpl">
    <div>
        <h2>這是建立全域性元件的第三中方式</h2>
        <p>嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿</p>
    </div>
</template>

在這裡插入圖片描述
既然是全域性元件,那麼就可以重複呼叫,栗子:

<div id="app">
<mycom3></mycom3>
</div>
<div id="app2">
    <mycom3></mycom3>
</div>
<template id="tmpl">
        <h2>這是建立全域性元件的第三中方式</h2>
</template>

<script>
    Vue.component('mycom3', {
        template: '#tmpl'
    })
    var vm = new Vue({
        el: '#app',
    });
    var vm2 = new Vue({
        el: '#app2',
    });
</script>

在這裡插入圖片描述

三、建立私有元件

建立一個私有元件

<div id="app">
    <mycom4></mycom4>
</div>
var vm = new Vue({
      el: '#app',
      data: {},
      methods: {},
      components: { 
      // 定義例項中私有元件的   元件的名稱   和元件的 解構
        'mycom4': {
          template: '<h6>這是定義的私有元件</h6>'
        }
      }
});

建立多個私有元件:

<div id="app">
    <mycom4></mycom4>
    <mycom5></mycom5>
</div>
components:{
            mycom4:{
                template:'<h2>這是我定義的私有元件1</h2>'
            },
            mycom5:{
                template:'<h2>這是我定義的私有元件2</h2>'
            }
         }

在這裡插入圖片描述

四、元件中相應資料和展示方法

 Vue.component('mycom', {
        template: '<h3 @click="show">這是自定義的全域性元件 ------ {{ msg }}</h3>',
        data: function () { //
            // 在 元件中,可以有自己的私有資料
            // 但是,元件的 data 必須是一個 function
            // 並且內部 return 一個 資料物件
            return {
                msg: '我是元件的內部data'
            }
        },
        methods: { // 嘗試定義元件的私有方法
            show() {
                // console.log('出發了元件的私有show方法!')
                alert('我是元件內部的方法')
            }
        }
    })

在這裡插入圖片描述

思考:
為什麼要把 元件中的 data 定義為一個function呢?
因為這樣做的話,每當我們在頁面上引用一次元件,必然會先呼叫 這個 data function,
從而得到一個當前元件私有的 資料物件;

五、切換元件

1. 結合flag識別符號和 v-ifv-else 實現元件的切換

<div id="app">
<!--    使用按鈕去控制顯示login和res-->
    <input type="button" value="顯示登入" @click="flag=true"/>
    <input type="button" value="顯示註冊" @click="flag=false"/>
  <login v-if="flag"></login>
<!--    當flag:true的時候顯示login-->
<!--    當flag:false的時候顯示res-->
    <res v-else="flag"></res>
</div>
<script>
    Vue.component('login', {
        template: '<h2>登入</h2>'
    })
    Vue.component('res', {
        template: '<h2>註冊</h2>'
    })
    // 建立 Vue 例項,得到 ViewModel
    var vm = new Vue({
            el: '#app',
            data:{
                flag:false
            },
            methods:{}
        })
</script>

在這裡插入圖片描述

2. 切換多個元件

<div id="app">
<!--想要顯示哪個元件就在:is屬性的後面傳入(字串)=====> '元件的名字'-->
   <component :is="'com1'"></component>
   <component :is="'com3'"></component>
    
</div>
Vue.component('com1', {
        template: '<h2>我是第1個元件</h2>'
    })
    Vue.component('com2', {
        template: '<h2>我是第2個元件</h2>'
    })
    Vue.component('com3', {
        template: '<h2>我是第3個元件</h2>'
    })
    Vue.component('com4', {
        template: '<h2>我是第4個元件</h2>'
 })

在這裡插入圖片描述
進行多元件的切換

<div id="app">
<!--點選a連結,修改component的值
component標籤結合is屬性進行元件的切換-->
    <a href="#" @click="comname='com1'">顯示元件1</a>
    <a href="#" @click="comname='com2'">顯示元件2</a>
    <a href="#" @click="comname='com3'">顯示元件3</a>
    <a href="#" @click="comname='com4'">顯示元件4</a>
    
    <component :is="comname"></component> 
</div>
 var vm = new Vue({
        el: '#app',
        data:{
            comname:'com1'
        },
//當vue解析檔案到component標籤時,如果有:is屬性就會解析後面的字串"comname"
//然後去data中尋找這個變數 
//comname:'com1'
//正好是一個字串的變數的名稱,就會顯示名稱叫com1的元件
        methods:{}
 })

在這裡插入圖片描述

3.為元件切換新增動畫

 <transition>
        <component :is="comname"></component>
    </transition>
<style>
        .v-enter,
        .v-leave-to{
            opacity:0;
            transform: translate(100px);
        }
        .v-enter-active,
        .v-leave-active{
            transition: all 0.4s ease;      
        }
</style>

在這裡插入圖片描述
如上圖效果顯示,有標準流的影響,所以要脫離標準流的影響,讓離開的元件脫離標準流

<style>
.....

.v-enter-active,
        .v-leave-active{
            transition: all 0.4s ease;
            position: absolute;
 }
 </style>

在這裡插入圖片描述
如圖動畫效果是先進入再離開,如果想要實現先離開再進入,則只需要在transition中新增mode="out-in"

 <transition mode="out-in"> -
        <component :is="comname"></component>
 </transition>

在這裡插入圖片描述
如果想要實現離開往左走,進入往右走的效果,則:

<style>
       .v-enter {
            /* 即將進入時候的座標 */
            opacity: 0;
            transform: translateX(100px);
        }

        .v-leave-to {
            /* 離開時候,最終到達的位置 */
            opacity: 0;
            transform: translateX(-100px);
        }
</style>

在這裡插入圖片描述

六、父元件通過屬性繫結向子元件傳遞資料

  1. 把要傳遞給子元件的資料,作為自定義屬性,通過v-bind繫結到子元件身上
 <com :sonmsg="pmsg"></com>
  1. 在子元件中,不能直接使用父元件傳遞過來的資料,需要先用props 來接收一下
   props: ['sonmsg']
  1. 在接收父元件傳遞過來的props的時候,一定要和父元件中傳遞過來的自定義屬性名稱保持一致
 template: '<h2>我是子元件-----{{sonmsg}}</h2>',

具體程式碼如下:

<body>
<div id="app">
    <com :sonmsg="pmsg"></com>
<!--    以屬性繫結的方式將父元件中的值傳遞給子元件-->
<!--    這裡相當於把 '我是父元件中的資料'放在這邊 也就是 msg123='我是父元件中的資料'-->
<!--    但是如果子元件想用msg需要在子元件中定義一下-->
</div>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
           pmsg:'我是父元件中的資料'
        },
        methods: {},
        components: { // 定義私有元件
            'com': { // 在Vue中,預設,子元件無法直接獲取父元件中的資料
                template: '<h2>我是子元件-----{{sonmsg}}</h2>',
                props: ['sonmsg']
               // 在Vue中,只有 props 是陣列,其它帶 s 字尾的屬性都是 物件
            }
        }
    });
</script>
</body>

在這裡插入圖片描述

七、父元件向子元件傳遞物件

  1. 把要傳遞給子元件的物件,作為自定義屬性,通過v-bind繫結到子元件身上
  <com1 :msgobj123="msgObj"></com1>
  1. 在子元件中,不能直接使用父元件傳遞過來的物件,需要先用props 來接收一下
 props: ['msgobj123']
  1. 在接收父元件傳遞過來的props的時候,一定要和父元件中傳遞過來的自定義屬性名稱保持一致
 template: '<h3>後面傳遞的是父元件中物件 ---- {{ JSON.stringify(msgobj123) }}</h3>'
template: '<h3>哈哈 {{ JSON.stringify(msgobj) }}</h3>',

具體程式碼如下:

<body>
<div id="app">
    <com1 :msgobj123="msgObj"></com1>
</div>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            msgObj: {
                id:1,
                name:'千夏Chinatsu',
                age:18
            }
        },
        methods: {},
        components: {
            'com1': {
                template: '<h3>後面傳遞的是父元件中物件 ---- {{ JSON.stringify(msgobj123) }}</h3>',
                props: ['msgobj123']
            }
        }
    });
</script>
</body>

在這裡插入圖片描述

八、父元件向子元件傳遞方法

  1. 把要傳遞給子元件的方法,通過v-on繫結事件到子元件身上
<com v-on:func="show()"></com>
  1. 在子元件中,不能直接使用父元件傳遞過來的方法,需要先用$emit() 來接收一下
  this.$emit('func')
  1. 在接收父元件傳遞過來的$emit()中,一定要和父元件中傳遞過來的方法名稱保持一致

具體程式碼:

<body>
<div id="app">
    <com v-on:func="show()"></com>
</div>

<script>
    var vm = new Vue({
        el:'#app',
        data:{},
        methods:{
            show(){
                console.log('觸發了父元件中的show()方法')
            }
        },
        components: {
            'com': {
                template: '<input type="button" value="這是子元件的按鈕" @click="btnClick()"/>',
                methods:{
                    btnClick(){
                        // console.log('hhhh')
                        this.$emit('func')
                    }
                }

            }
        }
    })
</script>
</body>

在這裡插入圖片描述

總結:
1.如果要向子元件傳遞 data 中的資料,則 使用 屬性繫結的形式 v-bind:
2. 如果要向子元件傳遞 methods 中的 方法,則 使用 事件繫結的形式 v-on:

九、子元件向父元件傳遞資料

<body>
<div id="app">
<!--    方式一:-->
    <com v-on:func="show"></com>
<!--    $emit('func',1)後面要傳遞引數-->
<!--   方式二:-->
<!--    <com v-on:func="show(2)"></com>-->
<!--    然後$emit('func')後面就不用傳遞引數-->
</div>
<script>
    var vm = new Vue({
        el:'#app',
        data:{},
        methods:{
            show(arg){
                console.log('觸發了父元件中的show()方法' + arg)
                // '--------'
            }
        },
        components: {
            'com': {
                template: '<input type="button" value="這是子元件的按鈕" @click="btnClick()"/>',
                data:function(){
                    return{
                        sonmsg:'這是子元件中的資料'
                    }
                },
                methods:{
                    btnClick(){
                        this.$emit('func','嘿嘿嘿嘿嘿')
                    }
                }

            }
        }
    })
</script>
</body>

在這裡插入圖片描述
所以可以直接在show()方法中傳入子元件中的data資料

methods:{
            show(arg){
                console.log('觸發了父元件中的show()方法' +'--------'+ arg)
                // '--------'
            }
        },
components: {
            'com': {
                template: '<input type="button" value="這是子元件的按鈕" @click="btnClick()"/>',
                data:function(){
                    return{
                        sonmsg:'這是子元件中的資料'
                    }
                },
                methods:{
                    btnClick(){
                        // console.log('hhhh')
                        this.$emit('func','嘿嘿嘿嘿嘿')
                        // this.$emit('func',this.sonmsg)
                    }
                }

            }
        }

在這裡插入圖片描述
把子元件傳遞過來的資料,儲存到 父元件的 data 中

methods: {
        show(arg) {
          // console.log('觸發了父元件中的show()方法' +'--------'+ arg)
          // 把子元件傳遞過來的資料,儲存到 父元件的  data 中
          this.msgFormSon = arg
          console.log(this.msgFormSon)
        }
 },

總結:
子元件向父元件傳值,本質上,還是呼叫了父元件傳遞過來的方法
只不過,子元件在呼叫的時候,把 資料 當作引數,傳給這個方法了;

十、練習列表案例(結合父子元件傳值)

<body>
  <div id="app">
    <!-- 評論框區域 -->
    <cmt-box @func="addNewCmt"></cmt-box>
    <ul>
      <cmt-item v-for="(item, i) in list" :item="item" :key="i"></cmt-item>
    </ul>
  </div>
  <script>

    Vue.component('cmt-item', {
      template: `<li>
        <h3>評論人:{{ item.name }}</h3>
        <h5>評論內容:{{ item.content }}</h5>
      </li>`,
      props: ['item']
    })

    Vue.component('cmt-box', {
      template: `<div>
      <label>評論人:</label>
      <br>
      <input type="text" v-model="name">
      <br>
      <label>評論內容:</label>
      <br>
      <textarea v-model="content"></textarea>
      <br>
      <input type="button" value="發表評論" @click="postComment">
    </div>`,
      data: function () {
        return {
          name: '',
          content: ''
        }
      },
      methods: {
        postComment() { // 發表評論
          // console.log('ok')
          const cmt = { name: this.name, content: this.content }
          // 子元件中,呼叫父元件傳遞過來的方法,然後可以把 子元件的資料,當作引數,傳遞給父元件的方法去使用
          this.$emit('func', cmt)
          this.name = this.content = ''
          // console.log(cmt)
        }
      }
    })
    var vm = new Vue({
      el: '#app',
      data: {
        list: [
          { name: 'zs', content: '沙發' },
          { name: 'ls', content: '板凳' },
          { name: 'qqq', content: '涼蓆' },
          { name: 'eee', content: '磚頭' }
        ]
      },
      methods: {
        addNewCmt(cmt) { // 新增新評論
          // console.log(cmt)
          this.list.push(cmt)
        }
      }
    });
  </script>
</body>

十一、使用rel屬性來獲取頁面中的元素

<body>

<div id="app">
 <input value="按鈕" type="button" @click="show()"/>
    <!--<h2 id="myh2">{{msg}}</h2>-->
    <!--加入ref屬性-->
     <h2 id="myh2" ref="hhh">{{msg}}</h2>
</div>

<script>
    var vm = new Vue({
        el:'#app',
        data:{
        msg:'嘿嘿嘿嘿嘿'
        },
        methods:{
            show(){
            //原生想要獲取h2中的資料的方法
               // var res = document.getElementById('myh2').innerHTML
               //console.log(res)
                console.log(this)
                console.log(this.$refs.hhh)
                console.log(this.$refs.hhh.innerHTML)
                
            }
        }
       })


</script>
</body>

在h2標籤中沒有加入ref屬性的列印console.log(this)結果

在這裡插入圖片描述
在h2標籤加入ref屬性的列印console.log(this)結果
在這裡插入圖片描述
所以可以通過rel可以很方便的來獲取元素

 console.log(this)
 console.log(this.$refs.hhh)
 console.log(this.$refs.hhh.innerHTML)
                

在這裡插入圖片描述

十二、使用rel屬性來獲取頁面中的元件

在這裡插入圖片描述
在這裡插入圖片描述
所以可以根據msg去修改元件內部的資料或者呼叫子元件中的方法

<body>

<div id="app">
    <input value="按鈕" type="button" @click="getCom()" />
    <com1 ref="xxxxx"></com1>

</div>
<script>
    Vue.component('com1', {
        template:'<h2>這是一個小元件---{{msg}}</h2>',
        data:function () {
            return {
                msg:'這是元件內部資料'
            }
        },
        methods:{
            show(){
                console.log('子元件中的方法被呼叫了')
            }
        }
    })
    var vm = new Vue({
        el:'#app',
        data:{
            msg:'這是父元件的資料'
        },
        methods:{
            getCom(){
                // console.log(this)
                this.$refs.xxxxx.msg = '元件內部資料被修改了'
                this.$refs.xxxxx.show()
            }

        }
    })
    //頁面上可以為很多元素建立ref的引用


</script>
</body>

在這裡插入圖片描述

十三、在vue元件中data和props的區別

  • data 在元件中,要被定義成一個function,並且要返回一個物件
  • props 在元件中,要被定義成陣列,其中,陣列的值都是字串名,表示從父元件傳遞過來的資料
  • props中的資料,不要直接拿來修改,如果想要修改,必須在data上重新定義一個屬性,然後把屬性的值從this.props直接拿過來
  • data 上的資料,都是元件自己私有的,資料都是可讀可寫的
  • props 都是外界傳遞過來的資料,資料只能讀取,不能重新寫入

相關文章