原文链接:Consider VueJS for Your Next Web Project
作者:Roman Kuba
VueJS是什么?
大致上,你可以把Vue(读音与view相同)理解为MV*当中的V层,如果非要和别的框架比较的话,你可以把Vue理解成为上手门槛很低的类React框架。不需要你学习JSX一类的奇葩语法,也不需要预编译,只要像往常引用类库一样,在你页面的header里面加一个vue的引用链接,就可以开始使用啦。而从Vue的模板标记里,你可能会找到Angular或Mustache等框架的影子。
接下来我们聊聊VueJS为什么这么有吸引力吧。
数据驱动 vs DOM驱动
解耦的思维方式在软件开发中很常见。一般在界面开发中,我们经常会以如下这种逻辑编写代码:
function textReturningFunction () {
return 'Hello World!'
}
// 使用jQuery来在DOM中输出内容
$('.someElement').text(textReturningFunction())
在我刚开始工作的时候,经常会写出类似的代码。但你只要仔细考虑一下就会发现,这类代码离真正的解耦还有很大的差距。
在这样的代码中,JS逻辑的实现对你的DOM结构依赖是相当大的。例如你把DOM中的.someElement这个节点改名为.some_element之后,虽然Hello World!还能被返回,但是与DOM的绑定失效了,你的JS就无法正常运行了,这也就是所谓DOM驱动的JS编码方式。
我们再来拿VueJS实现与上述相同的逻辑:
HTML
<div class="app">
<span class="someElement">
{{ msg }}
</span>
</div>
JS
new Vue({
el: '.app',
data: {
msg: 'Hello World!'
}
})
在这个用VueJS实现的例子中,最后会渲染出<span class="someElement">Hello World!</span>的结果,而你可以随意修改span的属性名,因为这段JS并不依赖它的属性名来查找操作DOM的内容。
整块代码中,我们只需要在声明Vue实例时指定.app容器,Vue就可以在其内部处理逻辑。
响应式(Reactivity)
Vue中所有的变量都是响应式的。这也就意味着他们都能被观察到,也能附加watchers在上面,当变量改变时就会通知触发相应的事件。你可以阅读Vue官方的文档中深入响应式原理这一篇。
为了方便你理解,我们可以拿Vue的实现同Angular的“脏检查”做对比。
在Angular中,某个数据发生改变时,它就会开始搜索这个改变,将所有新的数据与旧的比较完之后,再修改变化的部分,当应用架构复杂之后,这样的操作就相当耗费资源和时间了。
Vue使用的响应式数据系统在初始化时可能会耗用一些资源,但解决了之后的许多麻烦。
组件
Vue灵活简单的架构也沿用了组件的概念。组件就是简单并可以被重复利用的界面模块。当然其实现在所有流行的JS框架都沿用了组件化的思想。Web Components的解决方案出现也有些时日了。问题始终是浏览器范围的实现。
Vue通过提供一个独立于浏览器的组件系统来解决这个问题。你可以在官方文档组件了解更多。
我们为什么选择VueJS
在我们的应用中,我们需要开发一个交互非常重的页面,需要渲染服务器端控制台的输出给用户,有很多现实的问题需要解决:
- 修复可能导致浏览器卡死的性能问题
- 优化渲染效率
- 让代码更加易读可用
- 尽量减小引入新技术的成本
其实最早我们用的是Angular.我们需要从服务器传输大量控制台输出的字符串。之后再渲染到客户端的界面中。我们发现Angular渲染的效率并不够好。当数据达到一定量时,浏览器就会卡死。最终我们发现瓶颈在于Angular的scope而不是传输的数据量,因为Angular总是会追踪保存DOM所有的变化。
我们需要一个对DOM关注更少,而又不需要完全改变已有架构的工具。Vue看起来能满足我们的这些需求。
经过测试,使用Vue并没有发现明显的性能问题,渲染一万行内容都不在话下。权衡之后,我们就正式开始使用VueJS啦。
VueJS初步应用
第一步对Vue的应用,当然是要用它来重构页面。例如我们要渲染一个页面的侧边栏:
<!-- Application Example -->
<div id="app">
<aside>
<ul class="services">
<li v-for="service in services">
{{ service.name }}
</li>
</ul>
</aside>
</div>
发觉这段代码有多好读了吗?即使你从来没有接触过Vue,代码本身也很好理解。对于services数组当中的每个service对象,我们要渲染出一个包含service名称的li元素。
再来看看JS部分:
new Vue({
el: '#app',
data: {
services: [
{name: 'first service'},
{name: 'second service'}
]
}
})
在浏览器中运行之后就会得到:
<!-- Rendered HTML -->
<div id="app">
<aside>
<ul class="services">
<li>first service</li>
<li>second service</li>
</ul>
</aside>
</div>
接下来再引入Vue的组件实现:
<!-- Application Example -->
<div id="app">
<aside>
<ul class="services">
<!-- Placeholder for the component -->
<jet-service v-for="service in services" v-bind:service="service"></jet-service>
</ul>
</aside>
</div>
组件的实现方法也非常好理解:
//声明一个Vue组件
var JetServiceComponent = {
// 声明组件属性,通过 v-bind:service="service" 来绑定数据
props: ['service'],
// 组件输出的HTML模板
template: `
<li>
<strong>{{ service.name }}</strong>
</li>
`
}
new Vue({
el: '#app',
data: {
services: [
{name: 'first service'},
{name: 'second service'}
]
},
//注册Vue应用中要使用的组件
components: {
'jet-service': JetServiceComponent
}
})
使用Vue的门槛非常低,你并不需要引入一大堆模板代码再开始。你只需要熟悉JS的对象和方法就可以把Vue用得很溜了。
VueJS深入应用
有时候我们会需要渲染一些包含复杂嵌套的数据,例如下面这个例子:
[
{ name: "some step", type: "step"},
{ name: "step group", type: "group_step", steps: [
{ name: "grouped step alpha", type: "step"},
{ name: "grouped step beta", type: "step"},
]}
]
这时组件就需要根据数据类型的不同来进行不同的调用和渲染,为了实现这个需求,我们需要应用计算属性和条件渲染的概念:
var JetStepsComponent = {
name: 'jet-step',
props: ['step'],
// 通过计算属性保存每次调用组件的数据类别
computed: {
isGroupStep: function () {
return this.step.type === 'group_step'
}
},
// 通过条件渲染标记对不同类别的数据返回不同的输出
template: `
<li>
<span>{{ step.name }}</span>
<ul v-if="isGroupStep">
<jet-step v-for="step in step.steps" v-bind:step="step"></jet-step>
</ul>
</li>
`
}
综上所述,Vue就是这么的简洁高效。
为什么VueJS对你有用?
这世上并没有能解决一切需求的完美框架。所有脱离上下文对比框架好坏的做法都是耍流氓。每个框架都有各自适用的场景。Vue对我来说高效又好用,它只专注于解决一个问题:将数据渲染到页面中。而与此同时,Vue的生态圈也在不断发展壮大:
- 前端路由?你可以使用vue-router
- Ajax 异步请求?vue-resource(不过官方不再推荐),还可以使用axios
- 状态管理?Vuex
- 自动化构建?vue-cli并且vue的单文件组件等功能也能与Webpack/Browserify很好地协同使用。
总之,现在Vue越来越火了。有任何好的意见或建议以及对Vue的观点或看法欢迎在评论区参与讨论。