vue.js 组件知识总结

组件局部注册

<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

  • 接受一个value属性;
  • 在有新的value时触发input事件
  <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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339

推荐阅读更多精彩内容