vue.js 组件知识总结

2018-01-11  本文已影响68人  彤_姑娘

组件局部注册

<div id="app">
        hello vue
        <my-component></my-component>   
    </div>
    <script>
        var Child = {
            template:'<div>局部注册组件</div>'
        };
        new Vue({
            el:'#app',
            components:{
                'my-component':Child
            }
        })
    </script>

is 属性挂载组件

常见:ul、select、table
(字符串模板除外:.vue文件)

例:在table里使用组件无效,添加一个is属性。在is下往下写无效。

<div id="app">
        <table border="1">
            <tbody is="my-com"></tbody>
        </table>
    </div>
    <script>
       Vue.component('my-com',{
         template:'<tr><td>1</td><td>2</td></tr>'
       });

        new Vue({
            el:'#app'
        })
    </script>

props

数组和对象是引用类型,指向同一片内存空间,所以props是数组和对象时,修改子组件内容会影响到父组件。默认双向绑定。

数据验证

Vue.component('my-component',{
        props:{
            propA:Number, //必须是数字类型
            propB:[String,Number],
            propC:{//布尔值,如果没定义,默认是true
                type:Boolean,
                default:true
            },
            propD:{//数字,而且是必传
                type:Number,
                required:true
            },
            propE:{//如果是数组或对象,默认值必须是一个函数来返回
                type:Array,
                default:function (){
                    return [];
                }
            },
            propF:{//自定义一个验证函数
                validator:function(value){
                    return value > 10;
                }
            }
        } 
    })

自定义事件

v-on 监听自定义事件外,也监听DOM事件。用.native 修饰符表示监听的是一个原生事件,监听的是该组件的根元素。

<my-component v-on:click.native="handleClick"></my-component>

使用 v-model

  <div id="app">
        {{ value }}
        <my-com v-model="value" @click="minus"></my-com>
        <!-- 父向子:执行减操作 -->
        <button @click="minus">-1</button>
    </div>
    <script>
    // 点击add加一 把const++通过input事件把const传递出去
    Vue.component('my-com', {
        props: {
            // 这个必须叫value,并与input一一对应。不懂为啥?
            value: {
                type: Number
            }
        },
        template: '<div> {{ const1 }} <button @click="add">+1</button></div>',
        data() {
            return {
                const1: this.value
            }
        },
        methods: {
            add() {
                this.const1++;
                this.$emit('input', this.const1);   //必须为input
            }
        },
        watch:{
            value(val){
                this.const1 = val;
            }
        }
    });
    new Vue({
        el: '#app',

        data: {
            value: 1
        },
        methods: {
            minus() {
                this.value--;
            },
        }

    })
    </script>

非父子组件通信

推荐使用一个空 Vue 实例作为中央事件总线(bus),也就是一个中介。

<div id="app">
        {{ message }}
        <my-coma></my-coma> 
    </div>
    <script>
     // 创建空的bus实例 
    const bus = new Vue({
        //可以继续扩展bus
        //data,methods...
    });
     // 注册一个组件
    Vue.component('my-coma',{
        template:'<button @click="passEvent">click</button>',
        methods:{
            passEvent(){
                bus.$emit('msgInfo','come from children ');
            }
        }
    });
    new Vue({
        el:'#app',
        data:{
            message:''
        },
        mounted(){
            bus.$on('msgInfo',(msg)=>{
                this.message = msg;
            })
        }
    })
    </script>
非父子组件通信--父链、子链

this.$parent 可以在子组件中取到父组件的东西

this.$children 可以拿到app 实例里的所有子组件,如果有很多子组件,可以得到一个数组。

修改父(子)组件内容,最好不这么做!

非父子组件通--子组件索引

子组件索引只在组件渲染完成后填充,非响应式的,仅作为直接访问子组件的应急方案,应当避免在模板、计算属性中使用自定义子组件索引。

加载两个相同的组件,用ref 区分,如果需要for循环,可以动态绑定:ref="a"

<my-coma ref='a'></my-coma> 
<my-coma ref='b'></my-coma> 

取值:

this.$refs.a

slot 内容分发

当需要让组件组合使用时,要内容分发,混合父组件内容和子组件模板就叫内容分发。

<div id="app">
       <my-com>
           <!-- message生命周期由父组件或父实例来决定的,包括作用域,和my-com本身没关系。 -->
           {{ message }}
       </my-com>
   </div>
   <script>
       //hello world:
       // hello来自‘my-com’组件本身的内容,
       // world:父组件通过<slot>来充当的这部分内容
       Vue.component( 'my-com',{
           //slot 标签挂载内容,
           template:'<div>hello <slot></slot></div>',

       });

       new Vue({
           el:'#app',
           data:{
               message:'world'
           }
       })
   </script>

具名slot
在一个组件里,设置多个slot来区分显示的内容。(按照slot顺序展示:你好 朋友)

<my-com>
    <div slot="a">
        你好
    </div>
    <div slot="b">
        朋友
    </div>
</my-com>

script

<script>
        Vue.component( 'my-com',{
            template:'<div>hello <slot name="a"></slot><slot name="b"></slot></div>',

        });
        new Vue({
            el:'#app',
        })
    </script>

slot展示默认内容
如果组件里没有内容,就会显示slot里的默认内容。内容作用域只与当前组件(my-com)相关,与父组件无关。

<div id="app">
        <my-com></my-com>
    </div>

script

Vue.component( 'my-com',{
            template:'<div>hello <slot>这里是默认</slot></div>',
        });

访问slot
rander函数用的多

mounted(){
    this.$slots.default   //取默认内容
    this.$slots.a         //取a的内容
}

组件的高级用法

递归组件

满足条件:

  1. 必须给组件设置一个name。
  2. 在一个合适的时间结束组件的递归,否则报超栈的错误。
<div id="app">
        <my-com :count="1"></my-com>
    </div>
    <script>
        Vue.component('my-com',{
            name:'myCon',
            props:{
                count:{
                    type:Number,
                    default:1
                }
            },
            template:'<div><my-com :count="count +1" v-if="count<3"></my-com>{{ count }}</div>',
        });
        new Vue({
            el:'#app',
        })
    </script>

内联模板(少用)

给组件标签使用inline-template特性,组件就会把它的内容当做模板,而不是当做内容分发。会替代子组件的template来显示。

<div id="app">
    <my-com inline-template>
        <div>
            {{message}}
        </div>
    </my-com>
</div>

script

结果为:你好

<script>
        Vue.component( 'my-com',{
            // template:'<div>hello <slot>这里是默认内容</slot></div>',
            data(){
                return{
                    message:'你好'
                }
            }
        });
        new Vue({
            el:'#app',
            data:{
                message:'world'
            },
        })
    </script>

{{message}}作用域为组件内的data,有些难理解,少用吧~

异步组件

组件比较庞大时,使用异步组件

  1. 按需加载,可以节省首次加载的时间,提高速度,也算是一个性能优化。
  2. 那么一个组件可能会被使用多次,按需加载的话也不会加载多次,第一次加载完成就会缓存下来,和webpack是一样的,所以不用担心
    <div id="app">
        <my-com :count="1"></my-com>
    </div>
    <script>
        Vue.component('my-com',function(resolve,reject){
            window.setTimeout(function(){
                resolve({
                    template:'<div>from 异步加载组件</div>'
                })
            },3000)
        });
        new Vue({
            el:'#app',
        })
    </script>

$nextTick

等组件渲染完后使用

  this.$nextTick( () => {
      
  });

vue 如何观察数据变化?
并不是直接更新DOM,而是开启一个检查队列,缓存在一次事件循环中,缓存中会排除重复数据来避免不必要计算或DOM的操作,在下一次循环tick中,vue才会刷新队列,执行实际的操作。如果使用for循环动态改变100次数据,实际上只触发1次

检测:

vue 优先使用promise检测,不支持会使用HTML5新特性 Mutation Observer 的方法,都不支持采用setTimeout

x-template

前提是你没有使用webpack

 <div id="app">
    <my-com></my-com>
    <script type="text/x-template" id="my">
        <div>...</div>
    </script>  
</div>

手动挂载实例

一般使用 new vue 创建实例

new Vue({ 
    el:'#app'
})

在特殊情况下也可以动态创建 vue 实例。

vue提供两个API:

extend : 基础vue 构造器,创建了一个子类。参数包含组件选项的对象

$mount :挂载 (有很多参数,参见官网)

    <div id="app">
        hello Vue
    </div>
    <script>
    // 用extend 定义组件内容
        const myComponent = Vue.extend({
            template:'<div> from extend </div>' 
        });
    //通过 $mount 手动挂载在指定DOM里(通过工厂函数方法),支持class和id选择器
        new myComponent().$mount('#app');
    </script>

结果:from extend 覆盖 hello vue

问答模块

1.watch 与 computed 区别

watch:单纯监听某些东西变化,执行一些操作。

computed:根据已有的 data 或 props 的改变,来动态输出一个内容.常见的:排序、过滤、千位运算符等计算属性。

2.bus 怎么避免全局污染?

在 webpack 中,bus是一个bus.js文件,通过模块化就不会全局污染。

import bus from './bus.js'
3.mixins混合

把部分vue的配置merge到实例里,如:data、methods、props、计算属性、生命周期等内容,形成复用。

mixins:[]

组件解决UI的复用,mixins混合解决组件内部配置的复用

4.远程搜索(需要补充)

数据过多不建议使用select数据下拉。

5.keep-alive (需要补充)

让组件做缓存

文章内容参考:
Vue.js 实战之组件篇:https://segmentfault.com/l/1500000009448056/play
说说Vue的异步组件:https://juejin.im/entry/599562f36fb9a0249716d299
vue.js官网:https://cn.vuejs.org/v2/guide/components.html

上一篇下一篇

猜你喜欢

热点阅读