第七章:vue.js组件详解Ⅱ(基础篇)

7.5高级组件用法

        本节会介绍组件的一些高级用法,这些用法在实际业务中不是很常用,但在独立组件开发时可能会用到。如果你感觉以上内容已经足够完成你的业务开发,你可以跳过本节;如果你想继续探索Vue组件的奥秘,读完本节会对你有很多的启发。

7.5.1 递归组件

        组件在它的模板内可以递归的调用自己,只要给组件设置name的选项就可以了。示例代码如下:

 <div id="app">

    <child-component :count="1"></child-component>

</div>

<script>

Vue.component('child-component',{

    name:'child-component',

    props:{

        count:{

            type:Number,

            default:1

    }

},

    template:'\

    <div class="child">\

        <child-component :count="count+1"  v-if="count<3"></child-component>\

    </div>',

});

    var app =new Vue({

    el:'#app'

})

</script>

        设置name后,在组件模板内就可以递归使用了,不过需要注意的是,必须给定一个条件来限制递归数量,否则会抛出错误:max stack size exceeded.

        组件递归使用可以开发一些具有未知层级关系的独立组件,比如级联选择器(省市区)和树形控件(mytudolist)等。实战篇中,会详细介绍级联选择器的实现。

7.5.2 内联模板

        组件的模板一般都是在template选项内定义的,Vue提供了一个内联模板的功能,在使用组件时,给组件标签使用inline-template特性,组件就会把它的内容当作模板,而不是把它当内容分发,这让模板更灵活。示例代码如下:

<div id="app">

    <child-component inline-template>

        <div>

            <h2>在父组件中定义子组件的模板</h2>

            <p>{{ message}}</p>

            <p>{{ msg }}</p>

        </div>

    </child-component>

</div>

<script>

    Vue.component('child-component',{

        data:function(){

        return {

            msg:'在子组件声明的数据'

            }

    }

});

    var app = new Vue({

        el:'#app',

        data:{

            message:'在父组件中声明的数据'

            }

    })

</script>

        渲染后的结果为:

<div id="app">

    <div>

        <h2>在自父组件中定义子组件的模板</h2>

        <p>在父组件声明的数据</p>

        <p>在子组件声明的数据</p>

    </div>

</div>

            在父组件中声明的数据message和子组件中声明的数据msg,两个都可以渲染(如果同名,优先使用子组件的数据)。这反而是内嵌模板的缺点,就是作用域比较难理解,如果不是非常特殊的场景,建议不要轻易使用内联模板。

7.5.3 动态模板

        Vue.js提供了一个特殊的元素<component>用来动态地挂载不同的组件,使用is特性来选择要挂载的组件。示例代码如下:

<div id="app">

    <component :is="currentView"></component>

    <button @click="handleChangeView('A')">切换到A</button>

    <button @click="handleChangeView('B‘)">切换到B</button>

     < button @click="handleChangeView('C')">切换到C</button>

</div>

<script>

    var app = new Vue({

        el:'#app',

        components:{

        comA:{ template:'<div>组件A</div>'},

        comB:{ template:'<div>组件B</div>'},

        comC:{ template:'<div>组件C</div>'}

    },

        data:{

        currentView:comA

    },

        methods:{

        handleChangeView:function(component){

            this.currentView = 'com'+component;

        }

    }

})

</script>

        动态地改变currenView的值就可以动态挂载组件了。也可以直接绑定在组件对象上:

<div id="app">

    <component :is="currentView"></component>

</div>

<script>

    var Home={

          template:' <p>Welcome Home</p>'

    };

    var app = new Vue({

        el:'#app',

        data:{

        currentView:Home

    }

})

</script>

7.5.4 异步组件

        当你的工程足够大,使用的组件足够多时,是时候考虑下性能问题了,因为一开始把所有的组件都加载是必要的一笔开销。还在Vue.js允许将组件定义为一个工厂函数,动态地解析组件。Vue.js只在组件需要渲染时触发工厂函数,并且把结果缓存起来,用于后面的再次渲染。示例代码如下:

<div is="app">

    <child-component></child-component>

</div>

<script>

    Vue.component('child-component',function(resolve,reject){

        window.setTimeout(function(){

        resolve({

            template:'<div>我是异步渲染</div>'

        });

    },2000)

});

    var app = new Vue({

        el:'#app'

})

</script>

        工厂函数接受一个resolve回调,在收到从服务器下载的组件定义时调用。也可以调用reject(reason)指示加载失败。这里setTimeout只是为了演示异步,具体的下载逻辑可以自己决定,比如把组件配置写成一个对象配置,通过Ajax来请求,然后调用resolve传入配置选项。

        在进阶篇里,我们还会介绍主流的打包编译工具webpack和.vue单文件的用法,更优雅地实现异步组件(路由)。


7.6 其他

7.6.1 $nextTick

        我们先来看这样一个场景:有一个div,默认用v-if将它隐藏,点击一个按钮后,改变v-if的值,让它显示出来,同时拿到这个div的文本内容。如果v-if的值是false,直接去获取div的内容是获取不到的,因为此时div还没有创建出来,那么应该在点击按钮后,改变v-if的值为true,div才会被创建,此时再去获取,示例代码如下:

    <div id="app">

        <div id="div" v-if="showDiv">这是一段文本</div>

        <button @click="getText">获取div内容</button>

    </div>

<script>

    var app =new Vue({

        el:'#app',

        data:{

        showDiv:false

    },

        methods:{

        getText:function(){

            this.showDiv =true;

              var text =document.getElementById('div').innerHTML;

                console.log(text);

        }

    }

})

</script>

        这段代码并不难理解,但是运行后在控制台会抛出一个错误:Cannot read property 'innerHTML' of null,意思就是获取不到div元素。这里就涉及Vue一个重要概念:异步更新队列。

        Vue在观察到数据变化时并不是直接去除重复数据,从而避免不必要的计算和DOM操作。然后,在下一个事件循环tick中,Vue刷新队列并执行实际(已去重的)工作 。所以如果你用一个for循环来动态改变数据100次,其实它只会应用最后一次改变,如果没有这种机制,DOM就要重绘100次,这固然是一个很大的开销。

        Vue会根据当前浏览器环境优先使用原生的Promise.then和MutationObsever,如果都不支持,就会采用setTimeout代替。

        知道了Vue异步更新DOM的原理,上面示例的报错也就不难理解了。事实上,在执行this.showDiv=true时,div仍然还是没有被创建出来,直到下一个Vue事件循环时,才开始创建。$nextTick就是用来知道什么时候DOM更新完成的,所以上面的示例代码修改为:

…………

    this.showDiv=true;

    this.$nextTick (function(){

                   var text =document.getElementById('div').innerHTML;

                console.log(text);

});

…………

        这时再点击按钮,控制台就打印出div的内容”这是一段文本“了。

        理论上,我们不应该去主动操作DOM,因为Vue的核心思想就是数据驱动DOM,但在很多业务里,我们避免不了会用一些第三方库,比如swiper等,这些基于原生JavaScript的库都有创建和更新及销毁的完整生命周期,与Vue配合使用时,就要利用好$nextTick..



上一章:第七章:vue.js组件详解Ⅰ(基础篇)

下一章:第八章 vue.js-自定义指令(基础篇)

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

推荐阅读更多精彩内容