最近都是用element-ui 在协助自己的项目开发,用着用着就想看看饿了么是怎么实现组件的使用的,于是就想自己动手也来写,当然,我是要循序渐进的,从最开始最简单的组件定义开始。总的写了三个小组件,我按照我自己觉得难度等级,分别定义为基础版,打怪版,终极版。
项目在线demo
项目在线演示demo(切换到移动端调试模式哦)
项目github地址
项目github地址
嗯,在写之前,我先说一下,我会这篇文章中写下面三个小组件中的其中两个。分别如下所示:
- 基于vue的backTop 返回顶部小组件 --------- 普通版
- 基于vue的下拉菜单小组件 ----------打怪版
- 基于vue的侧边栏导航菜单的小组件 ------------------终极版
在编写组件的时候,复用组件是很有好处的。可复用组件应该有一个清晰的公共接口。
Vue组件的API来自三个部分:props events slots
- props: 允许外部环境传递数据给组件。
- Events: 允许组件对外部环境产生副作用。
- Slots: 允许外部环境将额外的内容组合在组件内部。
那么,其实我们可以用v-bind和v-on的简写语法,来使得模板清楚简洁:
// 这是我写的backTop 组件的调用方法。
// 用props将外部环境数据传递进去。
额,我觉得还是直接动手开始做吧,会比较实在一点,那就从最简单的backTop组件开始吧。
一 基础版: backTop返回顶部组件。
1.1最终的实现效果:
页面右下角就是自己封装的backtop组件。
1.2 外部组件调用的方式:
//这个scrollmyself是传进去组件的props值,
1.3 组件自定义方式
先说一下功能情况,这个backTop组件的作用就是,当页面存在滚动条,或者页面中某个局部有存在滚动条,当页面滚动到一定位置之后,页面就会出现点击返回顶部的按钮,点击之后就会返回顶部,此时返回顶部的icon消失。
- 1 .定义组件的基本功能结构
- 2 . 定义组件的install将组件export出去
- 3 在项目的main.js中使用调用组件。
首先看一下文件结构:
1 backtop内部的main.vue文件
-------- template模板
----------组件名: name: BackTop
----------props: 定义props数据格式,默认为false;true的时候当前发生滚动的对象就是内部引用该组件的父组件,为false的时候就是window对象。
// CSS部分:
2 引出组件:
在我们的component的内部的index.js文件中,我们需要将组件引出;
import BackTop from './backtop/src/main';
/* istanbul ignore next */
BackTop.install = function(Vue) {
Vue.component(BackTop.name, BackTop);
};
export default BackTop;
3 在main.js内部引用
import backTop from './myComponent/backtop'
Vue.use(backTop)
总结一下: 在上面这个backtop组件中,用props进行数据的传递,将数据传递给内部组件。
接下来这个侧边栏多级下拉导航侧边栏,实现的最终效果如下所示。
二 终极版本: sideBar侧边栏组件。
2.1 最终的实现效果:
侧边栏组件可以实现多级下拉菜单,同时也可以实现路由的跳转,只要设置相应的route值就可以。
2.2 组件的基本结构
因为这个组件是侧边栏组件,有单个的子菜单,也有包含有下拉子菜单的菜单,同时,所有我分成三个小的组件来实现。
同时也会使用slot来进行内容的分发。
基本的结构如下所示:
其实这个组件对于我来说,存在几个难点。
-
1 首先这是一个可以多级下拉菜单的组件,那么基本的结构和样式就很重要,如何让子菜单下的子菜单每次都依次往右边移动大概20px的距离,可以凸显出菜单之间的级别关系。
-
2 其次是点击每一个含有子菜单的标题,如何让其显示下拉菜单,而且是下拉的样式来显示的,同时要保证再深一层次的下拉菜单不会显示出来。
-
3 我会用一个props来从父组件向子组件传递数据,通过
props myVisible
来控制导航侧边栏的出现与消失。同时你也会发现,通过点击蒙板(在组件内部定义)也可以实现侧边栏的消失,如何实现双向数据传递呢?
待会我会提到这两个问题,不过我们可以先来看一下这个组件引入(怎么引入我待会说,跟上面的一样)之后的使用范例:
我的个人助手小系统呀
首页
DatePlan
今天吃什么
备忘录
什么时候放假
抛硬币
照镜子
记账
记账首页
添加记账
这是有下拉菜单
我是第一个
我是第二个
这是有下拉菜单
我是第一个
我是第二个
这是有下拉菜单
我是第一dddddd个
我是第二ddddddddddddd个
基本的使用结构,可以认真看例子代码。具体的细节我就不说啦。
参数
[my-menu 组件] myVisible : 默认为false,控制侧边栏的显示与消失。
[menu-item组件] route : 默认为空,控制路由的跳转。
slot
[my-menu 组件] menu-title: 控制菜单的标题显示
[menu-item组件] icon: icon图标的显示。
[my-submenu组件] submenu-title: 子级菜单的标题显示。icon: icon图标的显示。
2.3 组件的代码结构
menu-item的结构
难点实现:这个渲染之后是每一个不含有子菜单的菜单,那么问题来了,当有绑定路由对象的时候,点击某个菜单的时候,侧边栏菜单是要消失的,那么如何,去告诉引用了menu-item组件的my-menu父组件去关闭呢?
解决方法:这里参考了饿了么组件的dispatch方法,(dispatch文件就不po出来了),向父组件传递事件。
引入了dispatch文件之后:
子组件中使用:this.dispatch('my-menu', 'closeByRoute')
监听的my-menu父组件:this.$on('closeByRoute', this.toggleShow)
my-menu的结构
前面提到,my-menu组件是用props myVisible来实现侧边栏的显示与消失。因为vue是不可以直接修改prop属性的,但是新版的vue可以使用sync
来实现父子组件的双向数据绑定。
只要在调用的时候,使用
而在组件内部,想要变更props值的时候,只需要添加 this.$emit('update:myVisible', !this.myVisible)
来更新props属性值就可以。
http://www.cnblogs.com/penghuwan/p/7473375.html#_label1 大家可以参考一下这篇文章。
这个组件的主要就是用props来控制显示和隐藏。最主要的是toggleShow方法,控制侧边栏的显示和隐藏,通过添加一个togglehide 的类来判断当前的侧边栏是否是显示的状态。
my-submenu 组件。
含有子菜单的菜单引用,就需要引用my-submenu的组件。关于如何实现子菜单的下拉和收起的效果,这是这个组件的主要实现难点。
基本思路如下:
1 一开始先设置.treeview同级的treeview-menu菜单的display为none
2 当包含有子菜单的菜单即记账标签被点击之后,设置treeview-menu的样式height为0,首先设置为display:block,而且over-flow为hidden。然后获取当前的子菜单下的li个数,即可以获取所有子元素的高度,然后再设置treeview-menu的高度为该高度。
结合transition就可以实现下拉效果了。具体可以看代码。
这里设置display:block和设置高度不能同时设置,不然transition不会生效,可以设置一个小延时,设置为display:block之后,再设置高度。
在index.js中export组件
import mymenu from './sidebar//src/my-menu.vue'
import menuitem from './sidebar/src/menu-item.vue'
import mysubmenu from './sidebar/src/my-submenu.vue'
import BackTop from './backtop/src/main'
/* istanbul ignore next */
const components = [
mymenu,
menuitem,
mysubmenu,
BackTop
]
const install = (Vue, OPts) => {
if (install.installed) {
return
}
components.map(component => {
Vue.component(component.name, component)
})
}
export default {
version: '0.0.1',
author: 'katherine',
install,
mymenu,
menuitem,
mysubmenu,
BackTop
}
这里我将所有的组件都在这里export出去了。引用的时候,只要直接import整个文件就可以了。
main.js
import globalUI from './myComponent'
Vue.use(globalUI)
一个小技巧
关于怎么实现这些子菜单中的等级关系,就是越往下的子菜单就会依次增多一个
padding-left:20px;
的属性值。
其实可以看一下我的 my-submenu.vue 的结构
而当有多级下拉菜单的时候,我在外部引用的时候都是这样子去引用调用的。
而含有多级子菜单的,我都是直接在my-submenu内部再去嵌套添加,细心的你会发现,我的子菜单list都是存在一个这样的ul里面。
所以,我就在CSS样式中设置如下,这个很关键,这样的话,只要你不管嵌套多少层下拉菜单,都会依次增加一个padding-left:20px;的属性值。
.treeview-menu {
.treeview-menu {
padding-left:20px;
}
}
呼呼,感觉自己讲得太细节了,会不会反而会更混乱,但是这些是我在做的过程中遇到的问题,毕竟自己是小白,觉得很多东西如果不讲细节一点,一开始学肯定觉得很吃力,不知道要怎么深入。所以我都会希望自己能够详细地分享自己学习过程中所遇到的问题。也希望通过分享,自己也能从别人身上学到新的知识。
项目在线demo
项目在线演示demo(切换到移动端调试模式哦)
项目github地址(喜欢的话欢迎start~~~~)
项目github地址