从零开始学习Vue(三)
来源:互联网 发布:过敏源测试 知乎 编辑:程序博客网 时间:2024/06/05 05:08
我们从一个例子来学习组件,vuejs2.0实战:仿豆瓣app项目,创建自定义组件tabbar
这个例子用到其他组件,对于初学者来说,一下子要了解那么多组件的使用,会变得一头雾水。所以我把这个例子改写了一下,只需要依赖Vue.
然后最好FQ安装一个chrome的扩展 vue-devtools,这样可以更好看到组件的内容
组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。
在较高层面上,组件是自定义元素, Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以是原生 HTML 元素的形式,以 is 特性扩展。
父子组件的关系可以总结为 props down, events up 。父组件通过 props 向下传递数据给子组件,子组件通过 events 给父组件发送消息。
SLOT的理解: 子组件有名字的slot,将会给父组件同名的slot替换掉, 子组件匿名的slot, 将会给父组件的其他没slot名字的内容替换掉.
<m-tabbar-item id='tab1'> <img src="../assets/images/ic_tab_home_normal.png" alt="" slot="icon-normal"> <img src="../assets/images/ic_tab_home_active.png" alt="" slot="icon-active"> 首页 </m-tabbar-item>
子组件模板:
<a class="m-tabbar-item" :class="{'is-active':isActive}" @click="$parent.$emit('input',id)"> <span class="m-tabbar-item-icon" v-show="!isActive"><slot name="icon-normal"></slot></span> <span class="m-tabbar-item-icon" v-show="isActive"><slot name="icon-active"></slot></span> <span class="m-tabbar-item-text"><slot></slot></span> </a>
最终生成的HTML:
<a class="m-tabbar-item"><span class="m-tabbar-item-icon"><img src="../assets/images/ic_tab_home_normal.png" alt=""></span><span class="m-tabbar-item-icon" style="display: none;"><img src="../assets/images/ic_tab_home_active.png" alt=""></span><span class="m-tabbar-item-text">首页</span></a>
<img src="../assets/images/ic_tab_home_normal.png" alt="" slot="icon-normal"> 会替换掉 <slot name="icon-normal"></slot>
<img src="../assets/images/ic_tab_home_active.png" alt="" slot="icon-active"/> 会替换掉 <slot name="icon-active"></slot>,并把slot的名字去掉
首页 会替换掉 <slot></slot> 这个匿名的.
整个页面的代码如下:
<html xmlns="http://www.w3.org/1999/xhtml"><head> <title></title> <meta content="width=device-width,initial-scale=1,user-scalable=no" name="viewport" /> <script src="Scripts/vue.js" type="text/javascript"></script> <style type="text/css"> .m-tabbar { display: flex; flex-direction: row; position: fixed; bottom: 0; left: 0; right: 0; width: 100%; overflow: hidden; height: 50px; background: #fff; border-top: 1px solid #e4e4e4; } .m-tabbar-item { flex: 1; text-align: center; } .m-tabbar-item-icon { display: block; padding-top: 2px; } .m-tabbar-item-icon img { width: 28px; height: 28px; } .m-tabbar-item-text { display: block; font-size: 10px; color: #949494; } .is-active { color: #42bd56; } </style></head><body> <div > <div> <m-tabbar v-model="select"> <m-tabbar-item id='tab1'> <img src="../assets/images/ic_tab_home_normal.png" alt="" slot="icon-normal"> <img src="../assets/images/ic_tab_home_active.png" alt="" slot="icon-active"> 首页 </m-tabbar-item> <m-tabbar-item id='tab2'> <img src="../assets/images/ic_tab_subject_normal.png" alt="" slot="icon-normal"> <img src="../assets/images/ic_tab_subject_active.png" alt="" slot="icon-active"> 书影音 </m-tabbar-item> <m-tabbar-item id='tab3'> <img src="../assets/images/ic_tab_status_normal.png" alt="" slot="icon-normal"> <img src="../assets/images/ic_tab_status_active.png" alt="" slot="icon-active"> 广播 </m-tabbar-item> <m-tabbar-item id='tab4'> <img src="../assets/images/ic_tab_group_normal.png" alt="" slot="icon-normal"> <img src="../assets/images/ic_tab_group_active.png" alt="" slot="icon-active"> 小组 </m-tabbar-item> <m-tabbar-item id='tab5'> <img src="../assets/images/ic_tab_profile_normal.png" alt="" slot="icon-normal"> <img src="../assets/images/ic_tab_profile_active.png" alt="" slot="icon-active"> 我的 </m-tabbar-item> </m-tabbar> </div> </div> <script type="text/javascript"> Vue.component("m-tabbar", { props: ['value'], template:'<div class="m-tabbar"><slot></slot></div>' }); Vue.component("m-tabbar-item", { props: ['id'], computed: { isActive(){ if(this.$parent.value===this.id){ return true; } else return false; } }, template:'<a class="m-tabbar-item" :class="{\'is-active\':isActive}" @click="$parent.$emit(\'input\',id)">' +'<span class="m-tabbar-item-icon" v-show="!isActive"><slot name="icon-normal"></slot></span>' +'<span class="m-tabbar-item-icon" v-show="isActive"><slot name="icon-active"></slot></span>' + '<span class="m-tabbar-item-text"><slot></slot></span>' +'</a>' }); var app = new Vue({ el: '#app', data: { select:"tab1" } }); </script></body></html>
m-tabbar组件的双向绑定 v-model="select" 说明m-tabbar暴露出的属性value是和data里的select字段关联的,页面默认选中的是第一个tab,它的Id是tab1.
m-tabbar-item组件里有一个判断 this.$parent.value===this.id,父组件的value等于子组件的Id,则该子组件为选中的。
@click="$parent.$emit(\'input\',id)" 这个方法, 请参考这里 https://cn.vuejs.org/v2/guide/components.html#使用自定义事件的表单输入组件
<m-tabbar v-model="select">等价于 <m-tabbar v-bind:value="select" v-on:input="select=arguments[0]">
所以要让组件的 v-model 生效,它必须:接受一个 value 属性在有新的 value 时触发 input 事件
所以@click="$parent.$emit(\'input\',id)" 这个方法就是在子组件click的事件,触发父组件的input事件把子组件的Id传个父组件的value属性
问题来了:为什么父组件有个input事件呢? 它只是个div而已,我可以把这个事件名字改成其他的吗?
改成下面的代码,把事件名改成abcdef,是可以通过的
<m-tabbar v-bind:value="selectId" v-on:abcdef="tabSelect"> <script type="text/javascript"> Vue.component("m-tabbar", { props: ['value'], template:'<div class="m-tabbar"><slot></slot></div>', mounted: function () { console.log("m-tabbar mounted"); } }); Vue.component("m-tabbar-item", { props: ['id'], mounted: function () { console.log("m-tabbar-item mounted"); }, computed: { isActive(){ if(this.$parent.value===this.id){ return true; } else return false; } }, template:'<a class="m-tabbar-item" :class="{\'is-active\':isActive}" @click="$parent.$emit(\'abcdef\',id)">' +'<span class="m-tabbar-item-icon" v-show="!isActive"><slot name="icon-normal"></slot></span>' +'<span class="m-tabbar-item-icon" v-show="isActive"><slot name="icon-active"></slot></span>' + '<span class="m-tabbar-item-text"><slot></slot></span>' +'</a>' }); var app = new Vue({ el: '#app', data: { selectId:"tab1" }, methods:{ tabSelect:function(Id){ console.log("tabSelect"); this.selectId= Id; } } }); </script>
是任意名字都可以吗? 不是的,我试过有2个是不行的。 当事件名里有包含Select或者Index这2个词时,父组件就监听不到这个事件了。 难道这2个是什么保留字, 有人知道吗?
0 0
- 从零开始学习Vue(三)
- 从零开始学习Vue(三)
- 从零开始学习Vue(三)
- 从零开始学习Vue(三)
- 从零开始学习Vue(三)
- 从零开始学习Vue(三)
- 从零开始学习Vue(三)
- 从零开始学习Vue(三)
- VUE 学习笔记 从零开始一步一步构建 VUE 单页应用(三)
- 从零开始学习jQuery (三)
- Vue学习笔记三
- vue从零开始
- vue从零开始
- 从零开始学习jQuery(三)
- 从零开始学习RecyclerView(三)
- vue学习(三) vue组件
- Vue.js 学习(三)
- vue.js学习(三)
- math对象
- 无法获取焦点问题
- httpServletRequest.setCharacterEncoding 、httpServletResponse.setCharacterEncoding详解
- 图像卷积与滤波的一些知识点
- bzoj 2709: [Violet 1]迷宫花园 (最短路)
- 从零开始学习Vue(三)
- 模板方法模式在协议构造与解析中的应用
- 剑指offer-全排列(含重复数字)
- SQL基本语法
- 后缀数组模板 by hzwer
- java中有了基本类型为什么还要有包装类型?
- 题目1168:字符串的查找删除
- KCF目标跟踪方法分析与总结
- 儿歌