一个新手司机眼里的 Vue

1,442 阅读10分钟

先说一句题外话,对于 Vue 的探索和应用我只服 ElemeFE

基础

  • 软件工程学
  • 代码风格
  • 基本功
  • Vue.js 官方文档
  • ES6

Vue 三大特性

数据的双向绑定

通过数据绑定连接 View 和 Model, 让数据的变化自动映射为视图的更新。

数据驱动的组件系统

用嵌套的组件树来描述用户界面,每一个组件对应MVVM中的ViewModel。

基于构建工具的单文件组件系统

借助webpack强大的loader API,来定义对不同文件格式的预处理逻辑,从而将 vue 文件当作 javascript 模块来使用,从而极大提升了代码的可复用性。

开始

俗话说“工欲善其事必先利其器”,再往前递推,工欲利其器必先得其器。在进行一次 vue 项目的开发之前,如何将 vue 引入是我们面对的第一个问题。
这里我主要介绍两种引入方式。

传统的<script>大法

遥想当年,在和jQuery一起玩耍的时候,在每撸一个页面之前,都会先把jq的cdn路径放在处于</body>前的<script>里面,因为这样做才可以和她愉快的玩耍。
虽说 jq 和 vue 不是一个概念(库 vs 框架),但是基于浏览器解析js的原理,两者可以用相同的方式引入。

npm install

NPM(Node Package Manager)是Node.js自带的一款包管理工具,只需要简单的在键盘上敲下
npm install *package name*
就可以将你需要的包安装至你的项目中,进而借助模块加载器就可以把她们引入到你的文件中。
当然,除了npm之外,还有其他的包管理工具,比如 bower 和 yarn,可以根据个人喜好进行选择。
不过值得一提的是,yarn 是 Facebook 推出的一款包管理工具,他们的工程师在使用 npm 的时候发现了很多需要改进的地方,为了达到预期的效果,打造了 yarn 这款工具。所以,如果你感兴趣,可以试试 yarn

评估

对于上面两种方式的选择,你需要权衡一些因素:

  • 如果你是尝试在已有的项目中添加一点新鲜的血液作为预研,建议选择<script>标签的形式
  • 如果你是在从零开始搭建一个 vue 项目,建议选择用包管理工具的方式

为什么需要构建

要回答这个问题,就要追溯到另外一个问题:在将代码发布到生产环境之前,我们还需要做什么?
如果能回答好这个问题,我们就会知道——到底为什么需要构建?
答案可以大致分为以下几种:

  • 预处理
  • 代码风格检测
  • 资源压缩
  • 静态资源替换

因为本文侧重点的关系,这里说一下预处理
这又是另外一个问题了——为什么需要预处理?
因为无时不刻都在面临着浏览器的兼容问题,比如说ES6,一些语法糖写起来确实很爽,但是并不是所有浏览器都认识她;再者,React 的 jsx,Vue 的单文件,浏览器统统不认识,怎么办?只能预处理。
这里推荐 Vue 官方认证的好基友—— Webpack(其实我是gulp粉...)
如果你用的<script>来引入Vue,不用关注这个问题,因为你已经协助浏览器进行了“在线编译”。

组件化

Vue 的 slogan 是:轻量高效的前端组件化方案
这些年,伴随着 React 对 Web component 的不断实践与推动,组件化的思想被前端er们毫无抵触的接受,相比 React,个人认为 Vue 对组件化的解决方案更加优雅一些——借助构建工具的单文件组件系统
在一个.vue文件中,有三个主标签:<template>, <script>, <style>,分别对应着当前组件的结构、交互逻辑和样式。
口说无凭,举个栗子
先来看看 React 的 JSX

render(){
    let { item } = this.props;

    let children;
    if ( items.length > 0 ) {
        children = (
            <ul>
                { items.map( item =>
                    <li key={item.id}>{item.name}</li>
                ) }
            </ul>
        );
    } else {
        children = <p>No items found.</p>
    }

    return (
        <div className = 'list-container'>
            { children }
        </div>
    );
}

其实看起来也不是多么的不堪,能够利用完整的 JavaScript 功能来构建视图页面,也是一件有意义的事情。
相同的业务逻辑,用 Vue 来写

<template>
    <div class="list-container">
        <ul v-if="items.length">
            <li v-for="item in items">{{ item.name }}</li>
        </ul>
        <p v-else>No items found.</p>
    </div>
</template>

是不是比 React 的 jsx 语法和内联样式优雅的多呢?
你需要做的就是根据业务逻辑组织好你的 components tree,接着搭配一款模块化方案,就能实现一个基于 Vue 的单文件组件系统啦。
当然,Vue 也同样支持 jsx 语法,你也不必非得采用单文件的组织形式,一切都取决于你的业务以及你的团队。

Vue Object

每个 Vue 实例在被创建之前都要经过一系列的初始过程。Vue 在这一周期中提供了一些钩子函数,这就给我么提供了执行自定义逻辑的机会。

Vue 是否有“控制器”的概念?
答: 没有。但是你可以将组件的自定义逻辑分布并实现在这些钩子函数中。 、

附上一张描述 Vue 对象生命周期的官方神图 ↓

一个 Vue 实例的生命周期

做一下简单的翻译工作。

beforeCreate

在实例初始化之后,数据观测(data observer)和 event/watcher 事件配置之前被调用。

created

实例已经创建完成之后被调用。实例已经完成数据观测、属性和方法的运算、watch/event事件回调,但还没有开始挂载。

beforeMount

在挂在之前被调用

mounted

挂载之后

beforeUpdate

数据更新时调用,发生在 vdom 重新渲染和打补丁之前。

updated

由于数据更改导致的 vdom 重新渲染和打补丁,在这之后调用。

beforeDestroy

实例销毁之前调用。在这一步,实例仍然完全可用。

destroyed

实例销毁之后调用。

数据流 & 事件流

组装好了各个组件,你现在面临的问题是——如何让这些东西协同工作?

Props

props 是定义在子组件中的属性,用来定义期望从父组件传入的数据(在父组件中向子组件添加 v-bind 绑定属性即可)。

Event

  • 使用$on()监听事件
  • 使用$emit()触发事件
  • 使用$dispatch()派发事件,沿父链冒泡
  • 使用$broadcast()广播事件,传导给所有的后代

有时候,你也许需要一个帮手—— vuex

当应用比较庞大,数据流和状态也会越发的难以管理和维护,这个时候你就需要 vuex 了。

21秒精通 Vue.js

接下来从一个新手司机的角度,总结一些可以帮助你快速上手 Vue 的小经验。

不要一上来就用 vue-cli

连手枪都没打过,你一上来就问我要他娘的意大利炮?(一个出自《亮剑》的梗)

vue-cli是 Vue 官方推出的一款可以快速构建一个 vue app 的脚手架,各项配置也是全到没谁了。
但是,作为一个刚起步的选手,尤其是当你一开始要去搞的项目没那么复杂,还是不要用vue-cli了,原因有以下两点:

  • 如果你像我一样(对于构建玩的不是特别6),当你在Terminal按照指引敲击完几条命令之后,看着各种配置文件,肯定会一脸蒙蔽,会非常打击你的学习热情。
  • 更多的时候,你的项目可能还不需要用到如此完(yōng)整(zhǒng)的构建体系。

所以,自己动手搭一个吧,从最简单的开始,迟早有一天你也可以写出一个100%切合自己项目的脚手架。

你不仅需要ES6教程,还需要.babelrc

你是一个有理想的 JavaScript 开发者,你时刻关注着这门语言的发展趋势,终于有一天,你深深的迷恋上了ES6,她诸多的新特性都令你为之神往,所以你决定紧随她的脚步。
但事与愿违,很多浏览器在很大程度上并不认同这位姑娘,所以你需要作为中间人,让这些观念老旧的浏览器认识到新时代的风尚——这就是编译(此案例默认为预编译)。
通常情况下,我们在构建工具中引入babel对自己的脚本进行语法上的转换,实现向后兼容。
比如在webpack.config.js中引入这样的规则:

{
    test: /\.js$/,
    loader: 'babel-loader',
    exclude: /node_modules/,
    query: {
        presets: ['es2015', 'stage-0']
    }
}

事实证明,在大多数情况下,这样是ok的。
但,当我们的项目是借助构建工具实现的单文件组件系统时,我们的 JavaScript 都写在了.vue文件中,所以当你编译之后会得到一堆错误,这些错误都是在你使用ES6语法的地方出现的。
原因是因为我们用vue-loader去处理.vue文件,这本身没错。但是,vue-loader用到了babel-loader,却没有配置babel-loader的地方,所以呢,gg。
查看官方文档,就会找到解决办法。

“babel-loader respects .babelrc, so it is the recommended approach to configure the Babel presets and plugins.”

参加这里
综上,把 babel 相关配置放到 .babelrc 文件中去

使用组建之前先注册

想上车?先买票!

组件 (Components) 是 Vue.js 最强大的功能之一。

如果你没有使用那个单文件组件系统,在使用组件的时候,你要这么做 ↓ (注册一个全局组件Vue.component(tagName, options)

Vue.component('my-component',{
    // options
});

组件在注册之后,便可以在父实例的模块中以自定义元素<mu-component></my-component>的形式使用。
要确保在初始化根实例之前注册了组件

<div id="example">
    <my-component></my-component>
</div>
// 注册
Vue.component('my-component', {
    template: '<p>Hello Vue component</p>'
});

// 创建根实例
new Vue({
    el: '#example'
});

你也可以通过使用组件实例选项注册,可以使组件仅在另一个实例/组件的作用域中可用,这也是单文件组件系统的注册方式,即局部注册
官方文档写的已经非常详细了,如果你仍然对这里有疑虑,给你一个传送门

父子组件是怎么协同工作的?

父子组件的关系可以总结为 props down, events up
父组件通过 props 向下传递数据给子组件,子组件通过 events 给父组件发送消息。
这就好比,老子给儿子生活费(props),儿子一有事就告诉老子:“爸,我没钱了”、“爸,有人打我”、“爸,我饿了”(events)。

父子组件协作方式

让你更方便的调试 Vue

官方提供了一款 Chrome 插件,用于调试你的 Vue app —— Vue.js devtools

最后

全文是从个人的视角出发,描述对 Vue 的认识以及在开发过程中一些问题的理解。
如果有不正确、或是与你理解有偏差的地方,希望你能指出这些问题,共同学习。

一个还算有趣的前端