zoukankan      html  css  js  c++  java
  • 深入理解vue组件

    一、组件使用过程中的细节问题

    1.使用 is 解决H5标签的小bug(用 is='组件名' 解决)

    好处:这样的写法一方面可以使用组件,另一方面也符合H5的规范。

    /*创建组件*/
    Vue.component('row',{
        template:'<tr><td>this is a row</td></tr>';
    });
    /*vue实例接管#root*/
    new Vue({
        el:'#root'
    });
    <div id='root'>
        <table>
            <tbody>
                <row></row> <!-- 如果直接写组件名字,源代码渲染中会出错,<tr>标签会成为table的兄弟元素,-->
                <tr is='row'></tr> <!--正确写法:正常写<tr>标签,然后 is='row'(组件名)-->
                <tr is='row'></tr>
              </tbody>
          </table>
    </div>

    2.在子组件中定义 data 时,data 必须是个有返回值的函数,不能向父组件中一样定义。

    原因:子组件需要被网页中的元素多次使用,通过一个函数返回一个对象的目的,就是让每个子组件都拥有一个独立的数据存储,就不会出现多个子组件相互影响的问题。

    Vue.component("row",{   //组件名row
        data:function(){  //函数
            return {          //有返回值
                content:'this is a row'
            }
        },
        template='<li>{{content}}</li>'   //模板
    });

    3.获取DOM节点(vue是面向数据的开发,极少操作DOM)

    用法:

      1.在标签中添加  ref='ref名字'    例如:ref='hello'

      2.使用Vue内置属性获取,$.refs.ref名字  例如:$refs.hello

    当写在div标签中:使用 this.$refs.hello 获取的是 DOM节点

    当写在组件中:使用 this.$refs.hello 获取的是子组件的引用

    <div ref='dv' @click='dvClick'> ref 可以获取DOM节点 </div>
    new Vue({
        el:'root',
         methods:function(){
              dvClick:function(){
                   console.log(this.$refs.dv);   //<div> ref 可以获取DOM节点</div>
              }
          }
    }

    4.案例:计数器

    <div class="root">
        <row @change='sumChange' ref='num1'></row>  <!--第二步:监听子组件的触发事件,一旦触发事件,就执行sumClick方法-->
        <row @change='sumChange' ref='num2'></row>  <!--第二步:监听子组件的触发事件,一旦触发事件,就执行sumClick方法-->
        <div>{{total}}</div>
    </div>
    View Code
    // 全局子组件
    Vue.component('row', {
        data: function() {
            return {
                number: 0
            }
        },
        template: "<div @click='spanClick'>{{number}}</div>",
        methods: {
            spanClick: function() {
                this.number++;
                this.$emit("change"); //第一步:子组件向父组件触发一个名叫change的事件
            }
        }
    });
    // 实例组件
    new Vue({
        el: '.root',
        data: {
            total: 0
        },
        methods: {
            sumChange: function() {
                //console.log(this.$refs.num1.number);//获取子组件中number的值
                this.total = this.$refs.num1.number + this.$refs.num2.number;
            }
        }
    });
    View Code

    二、父子组件的数据传递

    1.父组件向子组件传递数据(属性)

    父组件通过属性的方式向子组件中传递数组

    <div count='0'> count后面跟的0 是字符串</div>
    <div :count='2'> :count后面跟着的2 是数字,因为:count后面的是表达式</div>

    子组件使用props接收父组件传递过来的数据

    var counter={
       props:['count'],   //接收父组件传递过来的数据
       template:'<div>{{count}}</div>' 
    };

    注意:

    有一个隐形规定:单向数据流

    在vue中有单向数据流的概念:父组件可以随意向子组件传递数据,但是子组件不能修改父组件传递过来的值。

    设置单向数据流,是为了防止,如果父组件传递过来的是对象形式的,在子组件中修改后,如果再被其他子组件引用,也会把其他子组件的数据一起更改了。

    解决方式:

    把父组件传递过来的值,赋值给子组件 data 中,找个数据接收。

    var counter={
        props:['count'], //接收父组件传递过来的数据
        data:function(){
            return {
                number:this.count   //把父组件的值赋值给子组件的data,此时再修改,不会影响父组件中的值
            }
        },
        template:'<div @click="dvClick">{{number}}</div>',
        methods:{
            dvClick:function(){
                this.number++;
            }
        }
    });
    View Code

    2.子组件向父组件中传递数据(通过事件传值)

    <div id='root'>
        <counter :count='3' @change='changeTotal'></counter><!--第二步:监听change事件,一旦触发,就执行changeTotal方法-->
        <counter :count='2' @change='changeTotal'></counter>
        <div>{{total}}</div>
    </div>
    View Code
    var counter={
        props:['count'],
        data:function(){
            return {
                number:this.count
            }
        },
        template:'<div @click="dvClick">{{number}}</div>',
        methods:{
            dvClick:function(){
                this.number++;
                this.$emit('change',1);  //第一步:每次点击时向外触发一个change事件,可以携带多个参数
            }
        }
    });
    new Vue({
      el:'root',
      data:{
        total:5
      },
      components:{  //把局部组件在实例中声明
        counter:counter
      },
      methods:{
        changeTotal:function(step){  //实现子组件触发事件,父组件监听到后的处理函数
          this.total+=step;
        }
      }
    });
    View Code

    三、组件参数校验与非props特性

    如果 子组件 要校验 父组件 参数 类型则:

    props: {
        //content:String   //校验参数 content 是否是 String 类型
        //content: [String, Number] //校验参数 content 是否为 Sting 或 Number中的一种类型
        content: {
            type: String, //类型
            required: false, //false:有没有都可以,true:必须有content这个变量
            default: '默认文本内容', //默认文本内容,如果有content属性,则显示content的内容
            validator: function(value) { //对传入的值校验
                return value.length > 5; //true 判断值的长度是否大于5
            }
        }
    }
    View Code

    props特性:

    1.要求父组件传参数,子组件要接收,然后可以在子组件中直接使用

    2.props特性,不会将属性显示在DOM的标签之中

    非props特性:

    1.父组件中定义了参数,子组件中没有接收,此时父组件中定义的参数就是非props特性,非props特性的内容,也就无法在子组件中使用。

    2.非props特性的元素会展示在子组件最外层的DOM标签的HTML属性里面

    四、给组件绑定原生事件(.native)

    方式一:给子组件绑定事件,通过父组件监听触发事件
    缺点:代码编写太麻烦
    <child @click='childClick'></child><!--在组件中定义的事件属于自定义事件,不是原生事件-->
    <!--方式一:给子组件绑定事件,通过父组件监听触发事件-->
    <child @change='clickEvent'></child><!--监听子组件中是否触发了change-->
    // 方式一:子组件绑定原生事件:直接在编写模板中绑定,通过向父组件触发事件达到效果,另外父组件中必须监听子组件的change事件有没有被触发
    Vue.component=({
        template:'<div @click='childClick'>此时绑定的是原生事件</div>,
        methods:{
            childClick:function(){
                this.$emit('change');//通过childClick的点击,向父组件中触发一个名叫 change 的事件
            }
        } 
    });

    方式二:

    更改监听事件的指向(.native)

    <child @click.native='childClick'></child><!--此时监听的不再是子元素的自定义事件,而是父组件的原生事件-->
    // 方式二:更改监听事件的指向(native)
    Vue.component=({
        template:'<div>child</div>',
    });
    new Vue({
        el:'#app',
        methods:{
            childClick:function(){
                console.log('通过子组件的@click.native可以直接调用此方法');
            }
        }
    });

    五、非父子组件之间传值

    也叫作Bus、总线、发布订阅模式、观察者模式

    <div id='root'>
        <child content='Dell'></child>
        <child content='Lee'></child>
    </div>
    Vue.prototype.bus=new Vue();  //vue原型属性bus,指向vue的实例,任何一个组件和实例中都有bus的属性
    Vue.component({
        props:{
            content:String   //判断接收的数据是否是String类型
        },
        data:{
            childContent:this.content
        },
        template:'<div @click="dvClick">{{childContent}}</div>',  //定义模板
        methods:{
            dvClick:function(){
                this.bus.$emit('change',this.childContent); //通过bus向整个vue触发一个change事件,并携带一个this.childContent的数据(此时其他子组件想使用这个数据,应该在组件中设置监听)
            }
        },
        //生命周期钩子:组件被挂载的时候执行的函数
        mouted:function(){
            var that=this;
            this.bus.$on('change',function(msg){
                that.content=msg;
        });
    });
    new Vue({
        el:'#root'
    });
    View Code

    六、Vue中的插槽(slot)

    方便向子组件中传递DOM元素

    <div class='root'>
        <child></child><!--子组件中没有DOM结构-->
    </div>
    
    Vue.component=('child',{
        template:`<div>
            <p>子组件内容</p>
            <slot>默认内容</slot>   /* 但是模板中定义了<slot>,则会显示插槽中默认文字 */
        </div>`
    });

    显示效果:

    <div class='root'>
        <p>子组件内容</p>
         默认内容
    </div

    具体使用方法:

    <div class='root'>
        <pages>
            <div class='header' slot='header'>header</div><!--向子组件中插入DOM节点-->
            <div class='footer' slot='footer'>footer</div><!--向子组件中插入DOM节点-->
        </pages>
    </div>
    new Vue({
        el:'.root'
    });
    Vue.component('pages',{
         template:`<div>
                             <slot name='header'>Header</slot> //name 指定显示哪个DOM结构,和DOM中的 slot 相呼应
                             <div class='content'>Content</div>  //原来子组件中要显示的内容
                             <slot name='footer'>Footer</slot>
                          </div>`
    });
    View Code

    七、Vue中的作用域插槽

     子组件模板可能在不同的地方被调用,不希望模板的样式被child给固定,希望模板样式由父组件告诉我们应该使用哪种样式

    <div class='app'>
        <child>
            <template slot-scope='props'>
                <h1>{{props.item}}</h1> <!--下面ul中的循环内容,父元素使用 h1 标签显示-->
            </template>
        </child>
    </div>
    /*
    父组件调用子组件时,给子组件传了一个插槽(作用域插槽),作用域插槽必须是<template>开头结尾的标签 ,同时作用域插槽要声明,要从子组件中接收的数据都放在哪(props)还告诉子组件一个模板的信息,接收到props后以什么形式展示。
    
    何时使用:当子组件做循环,或者某一部分由外部传递进来的时候,这时候就是用作用域插槽。
    
    子组件可以向父组件的插槽中插入数据。父组件传递过来的插槽如果想接收这个数据,必须在外层使用一个template ,同时通过  slot-scote 对应的名字(props)来接收子组件传递过来的所有数据
    
    子组件传了一个item 给父组件,在父组件的作用域插槽中就可以接收到这个item。
    */
    Vue.component('child',{
        data:function(){
            return {
                list:[1,2,3,4,5]
            }
      },
        template:`<div>
            <ul>
                <slot
                    v-for='item of list'
                    :item=item
                ></slot>
            </ul>
        </div>`
    });

    八、动态组件<component>与v-once

    v-once:会把数据存放在内容(提高加载静态数据的速度)

    template:'<div v-once>数据会被存放到内存中</div>'

    动态组件:会根据 is 里面的数据的变化,自动加载不同的组件(底层在切换时,会先销毁一个组件,然后展示另外一个组件(消耗性能))

    <div class='root'>
        <component :is='type'></component>
    </div>
    Vue.component("child-one",{
        template:"<div>child-one</div>"
    });
    Vue.component("child-two",{
        template:"<div>child-two</div>"
    });
    new Vue({
        el:'#root',
        data:{
             type:'child-one'
        },
        methods:{
            btnClick:function(){
                this.type=(this.type==='child-one'?'child-two':'child-one');
            }
        }
    });
  • 相关阅读:
    Python调用R语言
    走迷宫(用栈模拟实现非递归,并输出路径)
    走迷宫(用栈模拟实现非递归,并输出路径)
    《Python数据可视化编程实战》
    《Python数据可视化编程实战》
    一道思考题(二进制枚举的应用的想法)切金条
    Android 自己定义UI圆角button
    Oracle 用户管理(二)
    最大团解析及用处
    用反射完毕学生管理系统(包含数据库连接)
  • 原文地址:https://www.cnblogs.com/qtbb/p/12727877.html
Copyright © 2011-2022 走看看