• Vue 中的组件


    VUE中的组件

    一个自定义的标签,vue就会把他看成一个组件,vue可以给这些标签赋予一定意义;一个页面就是一个组件 
    好处:

    • 1、提高开发效率
    • 2、方便重复使用
    • 3、便于协同开发
    • 4、更容易被管理和维护

    自定义标签的书写规范: 

    1、组件名不支持大写字母(首字母可支持大写)

     2、html中采用多个单词用-隔开命名法,js中转换为对应的驼峰命名法

    注意:组件中的动态数据data数据必须是函数数据类型的,返回一个实例作为组件的数据。这样做是为了防止子组件之间公用数据导致的同时更新;(下面局部组件中有案例)

    全局组件

    用法:声明一次可以在任何地方使用

    //必须要先用component赋予自定义标签意义,然后再初始化实例
    Vue.component('my-hand',{
        template:'<div>{{msg}}</div>',
        data(){
            return {msg:'我很英俊'}
        }
    });
    let vm=new Vue({
         el:'#app'
    })
    //页面中使用
     <div id="app">
         <my-hand></my-hand>
     </div>

    局部组件

    用法:必须告诉这个组件属于谁,组件之间是相互独立的,不能直接跨作用域,vue的实例也是一个组件,拥有生命周期函数,理论上可以无限嵌套 
    1、创建局部组件(js) 
    2、注册这个组件(js) 
    3、在HTML中使用这个组件 
    注意事项: 
    1、子组件不能直接使用父组件的数据 
    2、组件理论上可以无限嵌套 
    3、子组件之间如果共用了数据,而且不把data写为返回一个对象的形式,会导致同时更新;

    //创建一个局部组件
       let handsome={
            template:'<div>{{msg}}</div>',
            //组件中的data必须是函数类型的,返回一个值作为组件的数据
            data(){
                return {msg:'我很英俊'}
            }
        };
        let handsome1={
            template:'<div>{{msg}}</div>',
            data(){
                return {msg:'我是在外部创建的局部组件'}
            }
        };
        let vm=new Vue({
            el:'#app',
            components:{
                //在components中注册局部组件
                handsome:handsome,
                handsome1:handsome1
                //在ES6中属性名和值相同可只写一个(上面的可简写为如下的形式)
                handsome,handsome1,
                //也可直接在components中直接创建和注册子组件
                handsome2:{
                    template:'<div>{{msg}}</div>',
                    data(){
                      return {msg:'我是在components中创建和注册的局部组件'}
                    }
                }
            }
        })
        //在页面中使用局部组件
        <div id="app">
            <handsome></handsome>
            <handsome1></handsome1>
            <handsome2></handsome2>
        </div>

    子组件之间公用数据导致的同时更新的问题;

      let obj={school:'zfpx'};
      let component1 = {
        template: `<div @click="school='hello'">组件一{{school}}</div>`,
        data(){
            return obj;//此种写法是错误的,点击组件一的时候会导致obj的数据更新,结果也会反映到组件二上
         }
      };
      let component2 = {
        template: '<div>组件二{{school}}</div>',
        data(){
            return obj;
        }
      };
      let vm=new Vue({
        el:'#app',
        components:{
          component1,component2
        }
      })
      //页面中使用
     <div id="app">
        <component1></component1>
        <component2></component2>
     </div>

    子组件与父组件之间的数据传递和嵌套

    嵌套

    //创建局部组件,相当于给grandson这个标签赋予了实际的意义
    //一定要先创建最内层的组件(即孙子)
        let grandson={
            template:'<div>{{msg}}</div>',
            data(){return {msg:'我是孙子'}}
        };
        let son={
            template:'<div>{{msg}}<grandson></grandson></div>',
            data(){return{msg:'我是儿子'}},
            components:{
            //在儿子中嵌套孙子组件
      //在son的components中注册了孙子组件后,才可在son的模版中使用grandson标签(但是依然不能在页面中使用son标签)
                grandson
            }
        };
        let parent={
            template:'<div>{{msg}}<son></son></div>',
            data(){return{msg:'我是父亲'}},
            components:{son}
        };
        let vm=new Vue({
            el:'#app',
            components:{
            //在vue的实例中注册了parent组件之后才能在页面中使用parent标签
                parent
            }
        })
        //在页面中使用局部组件
        <div id="app">
            <parent></parent>
        </div>

    数据传递

    父传递给子

    可以通过给子组件设置自定义属性的方式拿到父组件的属性值,子组件用props方法来获取到自定义属性的值就可以直接在子组件的模版中使用了;

    let vm=new Vue({
            el:'#app',
            data:{
                msg:100
            },
            components:{
                child:{
                //props属性写成数组的形式不能进行校验
                    props:['m'],//相当于取到子组件自定义的m属性,值是父亲的
               //写成对象的形式可以校验其值的类型
                   props:{
                      m:{
      //校验类型拿到的值是否属于下面的类型,不属于也会进行渲染,控制台会提示类型错误
                         type:[Number,String,Function,Object,Array],
                         default:0//如果子组件没有m属性,则m值默认取0
      //如果m属性是必须的,则可增加required:true(不可与default同用)
                         required:true
                        },
                   },
                    template:'<div>儿子{{m}}</div>'//这里就可以直接用m
                }
            }
        })
         //在页面中使用局部组件
        <div id="app">
            父亲:{{msg}}
    <!--m属于子组件的自定义的属性,前面加了:之后,m的值就变为动态的了->
            <child :m="msg"></child>//msg:拿到的是父的数据
        </div>

    子传递给父

    为了防止子组件无意间修改了父组件的状态,props采用的是单向绑定。所以子组件传递给父组件数据就不能通过设置自定义属性的方法,而要通过发布订阅模式来传递;

    let vm=new Vue({
            el:'#app',
            data:{
                money:400
            },
            methods:{
                things(val){//val:儿子触发事件时传过来的数据
                    this.money=val;
                }
            },
            components:{
                child:{
                    props:['m'],
                    //给儿子的按钮添加点击事件,当点击的时候触发发布订阅模式,执行绑定在子组件上的事件
                    template:'<div>儿子{{m}} <button @click="getMoney()">多要钱</button></div>',
                    methods:{
                        getMoney(){//此处的this指的是子组件的实例
                        //触发自定义事件(child),让父亲的方法(things)执行
                          this.$emit('child',800);
                        }
                    }
                }
            }
        });
        //在页面中使用子组件
        <div id="app">
            父亲:{{money}}
            <child :m="money" @child="things"></child>
        </div>

    组件中的插槽(slot标签)

    slot标签的作用:定制模版 
    slot相当于一个插槽,可以把组件中的对应标签拿到之后替换自己里面的内容 
    slot中可以放一些默认的内容,如果组件中对应slot值的标签有内容则会被替换掉,如果没有则会使用slot中的默认内容

       //js
        let model={
            template:'#model'
        };
        let vm=new Vue({
            el:'#app',
            data:{msg:'zf'}
            methods:{
                fn(){alert('是')}
            },
            components:{
                model
            }
        })
     //html
        <div id="app">
    <!--这里放的内容均属于父级模版的(如fn方法),所以必须在父模版的methods中写fn方法。msg属性也是父模版的。只有自定义的属性名是属于组件的(如m属性)-->
            <model :m="msg">
    <!--下面标签中的slot值与template中的slot是对应的,没有slot值的都会被放到default中-->
                <a href="www.baidu.com">百度一下</a>
                <p slot="content">确认删除?</p>
                <h1 slot="title" @click="fn">是否删除?</h1>
                <a href="www.baidu.com">百度一下</a>
            </model>
        </div>
        <!--模版中只能有一个根元素-->
        <!--slot作用,定制模版-->
        <!--slot相当于一个插槽,可以把组件中的对应标签拿到之后替换自己的内容-->
        <!--如果组件中没有标签,则使用slot中默认的内容-->
        <template id="model">
            <div>
                <slot name="title">默认标题</slot>
                <slot name="content">默认内容</slot>
                <slot name="default">这是一个默认标题</slot>
            </div>
        </template>

    如何在父组件中调用子组件中的方法

    通过给子组件设置ref值为xxx,在父组件中可通过this.$refs.xxx找到对应ref值的子组件的vue对象。(子组件的方法也挂载到了它的vue对象上) 
    由于在mounted执行时,子组件的DOM结构才加载完成,所以只有在mounted函数中才能用this.$refs.xxx.$el拿到对应子组件的DOM元素;

    let loading={
            data(){
                return{flag:true}
            },
            template:'<div>正在加载中……</div>',
            //子组件的方法
            methods:{
                hide(){
                //此方法中的this是子组件的vue对象
                    //hide执行的时候会把子组件的DOM元素背景色改为红色
                    this.$el.style.background='red';
                }
            },
     };
    let vm=new Vue({
          el:'#app',
          mounted(){
          //在此处实现父组件调用子组件的方法
            //此处的this是vm,this.$refs获取的不是子组件的DOM而是vue对象;
            // 可用this.$refs.load.$el来获取对应的DOM结构;
             this.$refs.load.hide();
          },
          components:{
             loading
          }
     })
     //Html
     <div id="app">
        <loading ref="load"></loading>
     </div>

    动态组件

    component标签 
    通过使用component标签,我们可以让多个组件使用同一个挂载点,并根据component内置的is属性来实现动态切换(is属性可以理解为是哪一个组件);

     let home={
            template:'<div>home</div>',
    //如果放在了keep-alive标签中,则可以保留它的状态来避免以后点击重新渲染。只在第一次渲染的时候会弹出1
            mounted(){alert(1)}
        };
        let list={
            template:'<div>list</div>',
     //如果放在了keep-alive标签中,则只在第一次点击的时候弹出2
            mounted(){alert(2)}
        };
        let vm=new Vue({
            el:'#app',
            data:{radio:'home'},
            components:{home,list}
        })
        //html
     <div id="app">
        <input type="radio" v-model="radio" value="home">home
        <input type="radio" v-model="radio" value="list">list
        <!--keep-alive标签一般用来缓存:现在讲是为了后面的路由做准备,如果缓存了,只会走beforeUpdate与之后的阶段-->
        <keep-alive>
            <component :is="radio"></component>
        </keep-alive>
     </div>

    keep-alive标签 
    如果想把切换出去的组件保留在内存中,可以保留它的状态或避免重新渲染。可以把需要缓存的标签外面包一个 keep-alive 标签

        <keep-alive>
            <component :is="radio"></component>
        </keep-alive>

    $nextTick的用法

    子组件和父组件都有mounted方法时,会先执行子组件的mounted方法:因为要保证子组件挂载完成再触发父组件的挂载

     let vm=new Vue({
         el:'#app',
        mounted(){//想操作最新的DOM,就需要用$nextTick方法(异步的来获取)
           //未加$nextTick方法,获取的不是最新的DOM
           console.log(this.$refs.child.$el.innerHTML);//结果为1,2,3
           //为了保证操作的是最新的DOM,则需要用$nextTick方法
           this.$nextTick(()=>{
               console.log(this.$refs.child.$el.innerHTML);//4,5,6(获取到的是最新的结果)
            })
        },
        components:{
            child:{
              data(){
                return {arr:[1,2,3]}
              },
              template:'<div><li v-for="a in arr">{{a}}</li></div>',
              mounted(){//先执行子组件的mounted方法之后再同步执行父组件的mounted方法
                 this.arr=[4,5,6]//此步骤涉及到DOM渲染,所以说是异步的,而执行父组件的mounted方法时,此步骤还未实现
              }
            }
        }
      })
      //html
     <div id="app">
        <child ref="child"></child>
     </div>

    同级组件之间的数据传递通过EventBus(不用,但要了解)

    为了保证订阅和执行的是同一个对象,需要借助第三方实例,通过第三方实例实现发布订阅 
    EventBus就是用来创建第三方实例的,可用来保证订阅和执行的时候是同一个对象

  • 相关阅读:
    选择器
    【兼容】text
    SQL2008的数据更新跟踪测试
    拖拽文件到RichEdit的后期处理
    Web Browser 的扩展
    URL Protocol Handler
    asterisk1.6异步脚本
    CSDNER如何才能做到"最不缺的是技术"
    关于SQL语句Count的一点细节
    TG787 脚本
  • 原文地址:https://www.cnblogs.com/webspace/p/8619679.html
Copyright © 2020-2023  润新知