• 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 都是外界传递过来的数据,数据只能读取,不能重新写入
  • 相关阅读:
    【404】int main(int argc,char * argv[]) windows 下的使用
    【403】COMP9024 Exercise
    【402】Twitter Data Collection
    【401】Python 求合数的所有质数因子
    【400】numpy.pad 为数组加垫(迷宫类题目)
    iOS开发之指纹解锁
    iOS-响应链(Responder Chain)
    iOS上手指点击波纹效果的实现
    使用methodSignatureForSelector与forwardInvocation实现消息转发 (转)
    Objective-C中的@dynamic(转)
  • 原文地址:https://www.cnblogs.com/Chinatsu/p/13893898.html
Copyright © 2020-2023  润新知