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


一、模塊化與組件化

  • 模塊化的定義

模塊化在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')
對應的組件標簽是 <my-com1></my-com1>
2. 如果是Vue.component('myCom1Test','com1')
對應組件標簽為: <my-com1-test></my-com1-tses>
3. 如果Vue.component('my-com1','com1')
對應組件標簽為: <my-com1></my-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>'

具體代碼如下:

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

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

<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)結果
在這里插入圖片描述
所以可以通過ref可以很方便的來獲取元素

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

在這里插入圖片描述

十二、使用ref屬性來獲取頁面中的組件

在這里插入圖片描述
在這里插入圖片描述
所以可以根據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 都是外界傳遞過來的數據,數據只能讀取,不能重新寫入


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM