系列文章的目录在 ? 这里html
除了 Vue.js 在 Weex 和 Web 中的差别之外,Vue.js 自身的各类特性都是能够正常使用的。因此,这篇文章其实和 Weex 并没多大关系,我就给你们简单罗列几个在 weex-hackernews 项目里用到的特性(这几个特性愈来愈高阶):vue
Vue mixin 文档node
mixin 是一种复用代码的技巧,能够将多个组件共同的逻辑抽象成 mixin,官方文档中写的很详细。它会将 mixin 中定义的方法合并到组件上,若是包含生命周期函数,则先调用 mixin 中的方法再执行组件自身的;若是属性有冲突,组件自身的方法会覆盖掉 mixin 中定义的。git
在 weex-hackernews 中的 src/mixin/index.js 里定义了一个简单的 mixin:github
export default { methods: { jump (to) { if (this.$router) { this.$router.push(to) } } } }
它只包含了一个方法,就是 jump
,它经过调用路由的 push
方法来实现页面跳转。web
而后,在 src/entry.js 中全局注册了这个 mixin
。shell
import Vue from 'vue' import mixins from './mixins' // register global mixins. Vue.mixin(mixins)
在实际应用中应该谨慎地注册全局 mixin,若是不是全局通用的操做,建议仍是只给用到的组件添加 mixin。apache
如此一来,全部组件都能调用到 jump
方法,例如 app-header.vue 这个组件,它自身没有 <script>
标签,可是可以在模板中给点击事件绑定 jump
函数。在 weex-hackernews 里,点击左上角的 logo 能够返回首页。segmentfault
<div class="logo" @click="jump('/')"> <image class="image" src="https://news.ycombinator.com/favicon.ico"></image> </div>
通常来讲你们都倾向认为组合要优于继承,在 Vue 里使用 mixin 实现“组合”,比用
ParentComponent.extend({})
模拟继承要好一些。并且在.vue
文件里,要想继承其余组件也挺麻烦的。从另一个角度上来说,若是真的是有一些逻辑能抽离出来,也优先考虑写成独立的模块,export
可用的接口,要用的时候直接import
进来便可。依赖框架自己的特性越少,代码就越容易复用。数组
在使用 v-bind
指令的时候,支持使用过滤器 (filter) 对绑定的值再进行处理;接收变量中的原始值做为参数,返回处理后的值,支持将多个过滤器串联在一块儿使用,相似 shell 命令中“管道”的写法。
过滤器的使用方法和 mixin
相似,如今 src/filter/index.js 中写好要注册的方法,在 src/entry.js 中全局注册了这些 filters
。
import Vue from 'vue' import * as filters from './filters' // register global utility filters. Object.keys(filters).forEach(key => { Vue.filter(key, filters[key]) })
在 weex-hackernews 的 story.vue 文件中第六行用到了 host
过滤器,用来获取 url 中的网站地址。
<text class="small-text" v-if="story.url">({{ story.url | host }})</text>
在第十三行用到了 timeAgo
过滤器,会把时间戳转成可读时间字符串。
<text class="small-text text-cell"> | {{ story.time | timeAgo }} ago</text>
在 src/filter/index.js 中的实现是这样的:
function host (url) { if (!url) return '' const host = url.replace(/^https?:\/\//, '').replace(/\/.*$/, '') const parts = host.split('.').slice(-3) if (parts[0] === 'www') parts.shift() return parts.join('.') } function timeAgo (time) { const between = Date.now() / 1000 - Number(time) if (between < 3600) { return pluralize(~~(between / 60), ' minute') } else if (between < 86400) { return pluralize(~~(between / 3600), ' hour') } else { return pluralize(~~(between / 86400), ' day') } }
效果以下:
除此以外
在 comment.vue 里用到了 unescape 过滤器。
在 ArticleView.vue 里用到了 https 过滤器。
<solt>
)槽是 Vue.js 中用来实现“内容分发”的功能的,能够理解为内容的占位符。参考 external-link.vue 例子:
<template> <div @click="open"> <slot></slot> </div> </template>
在 story.vue 里使用时,<external-link>
标签中的内容将会替换到 <slot>
。
<external-link :url="story.url" class="story-link"> <text class="story-title">{{story.title}}</text> <text class="small-text" v-if="story.url">({{ story.url | host }})</text> </external-link>
Vue 能够实现递归组件,能够在本身的模板中调用本身,只须要你写上 name
属性就能够了。
支持写递归组件,听起来好像是框架在故意炫技,为何会有这种奇葩功能?由于的确有这种奇葩需求…… 例如 Hacker News 里的评论,是能够无限展开的。
其实每条评论都有一个惟一 id
的,每条评论下边的回复的 id
都存在 kids
属性上;存的只是 id
不是真实的评论数据。从网络获取到某条评论以后,还有根据 kids
数组中的 id
获取评论下的全部回复,而后获取回复下的全部评论,而后获取评论下的全部回复…… 这很明显是个递归过程。即便评论的数据用树形结构去存,你不知道树的深度,仍是得用递归的方式把全部评论渲染出来。
【评论】和【回复】是一个意思,为了好表达才用的俩词,汉语就是比英语词多……
下面问题来了,如何渲染这种递归的评论?用正常的组件好像很难实现这种效果,我没想到很合适的写法,有兴趣能够试着想一下。
让组件支持递归很简单,只要加上 name
属性就好了,而后就能够在本身的模板中调用本身。
<!-- comment.vue --> <template> <div> <text>tips:</text> <comment></comment> </div> </template> <script> export default { name: 'comment' } </script>
上边就是一个最简单的递归组件的例子,写了 name
属性并且在模板中用了本身。可是它死循环了,没有结束条件,最终会报一个 "max stack size exceeded" 的错。
在 weex-hackernews 里,comment.vue 就是一个递归组件。它用于渲染一条评论,在内部有使用它本身渲染本身的评论。效果以下:
下边是 <comment>
组件简化后的核心代码:
<template> <div v-if="comment"> <text>{{comment.text}}</text> <comment v-for="id in comment.kids" :id="id"></comment> </div> </template> <script> import store from '../store' export default { name: 'comment', props: ['id'], computed: { comment () { return store.state.items[this.id] } } } </script>
在 <comment>
组件中,comment
属性的数据是根据当前的 id
属性从 store 中取出来的,而后根据 comment.kids
循环建立多个 <comment>
标签,而且把 id
属性传下去。子 <comment>
标签根据传递过来的 id
属性从 store 中获取 comment
数据渲染自身,而后根据 comment.kids
循环建立多个 <comment>
标签,而且把 id
属性传下去。…… 依次递归。
再具体的细节,就建议直接看 comment.vue 的代码了。至于 store 是如何获取数据的,关注后续讲 Vuex 的文章。
通篇讲的是 Vue 2.0 的特性,与 Weex 没有半毛钱关系,我想说明的是,这些特性在 Weex 里都是彻底可用的。
Vue 2.0 的特性比较多,能力很强大,这里只讲了很小一部分;只要思路清晰,各类奇葩效果也能优雅的实现。在 Vue 2.0 的全部特性中,只要不是强依赖与 Web 自己的特性,均可以在 Weex 里用。若是你对 Web 平台有足够的了解,在写代码的时候就能时刻清楚哪些特性是 Web / DOM 强相关的,哪些是跨平台通用的,这对你写跨端(Weex)或者跨栈(node.js)的程序颇有帮助。