Vue初探

前言

Vue.js (读音 /vjuː/,类似于 view) 是一套构建用户界面的渐进式框架 ,是由华人尤雨溪独立开发的一个前端框架,也是现在前端圈最火的前端框架之一,与之并列的有Google的Angular,Facebook的React,Vue 的核心库只关注视图层,它不仅易于上手,还便于与第三方库或既有项目整合,vue提供的脚手架令你可以快速的搭建一个简单的vue单页面应用(SPA :single page web application)

源起

在讲vue之前,我们先看一下前端的前世今生,那样会更好的理解和认知vue给我们带来了什么以及为什么要使用vue

前端模块化

以前的前端代码,基本都是刀耕火种年代的jQuery或原生js手写,如下面

1
2
3
4
5
6
for(var i=0; i<10; i++){
//........
}
element.onclick = function(){
//.......
}

很明显,这样若是业务逻辑越来越多,逻辑封装成函数之后,命名越来越多,在避免命名冲突问题上就消耗很多时间,外部文件引入层叠严重,JS文件引入层层依赖

1
2
3
4
<script type="text/javascript" src="a.js"></script>
<script type="text/javascript" src="b.js"></script>
<script type="text/javascript" src="c.js"></script>
<script type="text/javascript" src="d.js"></script>

上述的js文件引入就是噩梦一般,b.js依赖a.js,c.js依赖b.js,b.js依赖a.js,书写顺序不能乱,多人协同开发很难协调,后来人们开始使用匿名自执行函数或者类似于java风格的命名空间,但是还是换汤不换药,由此,js模块化规范正式进入人们的视野,一大波前端模块化规范涌现出来,如CommonJsAMD/RequireJsCMD/seajs 等等直到现在的ES6模块标准 ,而前端也因此终于开始走上台前

参考资料:

JavaScript 模块化历程

浅谈前端模块化

前端工程之模块化

模块化七日谈

说完前端js再来说下前端三驾马车之一的css(马上就要谈到vue了,不急哈),前端样式一直是个老大难的问题,甚至还诞生了专门的css工程师,由此可见,css并不像人们看起来的那么简单,当项目结构变大,页面重构的时候,频繁的修改css样式,更改css样式结构;浏览器兼容css样式书写;css的低复用性等等这些种种弊端都会让你在每一个书写css的深夜,都有种想要拿刀砍人的冲动,于是我们有了新朋友:css预处理器,例如sass,lesss,tylus以及处理浏览器兼容样式的postcss

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Mixin example
.btn-standout {
@extend .btn;
@extend .btn-block;

@media (max-width: $screen-xs-max) {
@include button-size(
$padding-large-vertical,
$padding-large-horizontal,
$font-size-large,
$line-height-large,
$border-radius-large
);
}

&.sell {
@extend .btn-primary;
}
}

虽然学习成本有点高,但是有了这些css预处理,我们可以得到:

  1. 函数,变量以及Mixin,复用css
  2. css模块化,改善项目结构
  3. 预编译,缓解多浏览器兼容造成的冗余
  4. ···

可以看到,有了css预处理器之后,可以让我们从繁杂冗余的css样式中摆脱出来,css代码结构也会更加的直观和清晰,开发时间和成本会减少到最低

前端构建

代码优化告一段落,但是这才只是刚刚开始,我们如果想要找出代码错误,想要压缩代码,想要自动检测代码修改,并且自动帮我们完成压缩检查的任务呢,接着我们有了强劲的新朋友:前端构建工具,诸如Gulp ,Grunt等,通过他们社区的插件。你可以轻易的做到上述所有

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
module.exports = function(grunt) {
grunt.initConfig({
uglify: {
'dist/all.min.js': ['dist/all.js']
},
jshint: {
files: ['gruntfile.js', 'src/*.js']
},
watch: {
files: ['gruntfile.js', 'src/*.js'],
tasks: ['jshint', 'concat', 'uglify']
}
});
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.registerTask('default', ['jshint', 'concat', 'uglify']);
};

上述的Gruntfile.js引入了uglify,jshint,watch插件,我们也因此可以做到压缩,代码检查,自动检测代码更改这三个效果,由此可见,前端构建工具极大地解放了人们的生产力(你也终于可以不用一行一行的去找你哪里代码写错了)

终于,你代码也写好了,代码也压缩了,现在需要部署打包了,你看了下,一百来个js,一百来个css,外加一千多张图片,每一个文件都会是一次请求,我估计等你家的网站资源加载完毕,你都已经出门买包烟回来了,这个时候,我们来个超级强劲的新朋友:前端打包工具,诸如webpack,yarn,rollup 等,超强劲的新朋友可以帮我们做到:

  1. 以模块化的方式来书写脚本,方便旧项目进行代码迁移
  2. 开发便捷,能替代部分 grunt/gulp 的工作,比如压缩混淆、图片转base64等
  3. 扩展性强,插件机制完善,特别是支持 热加载的功能
  4. ···

可以看到,利用前端打包工具bundle我们的项目,可以缩小文件体积,将多个文件合并成一个文件,减少http请求,对于我们的项目优化有着显著的作用

so, why vue?

其实我们用npm init一个项目,利用前端构建工具,npm install 相关的包,利用jQuery其实也是可以开发项目的,但是为什么要用vue,不同的框架会有不同的效果,利用jQuery我们可以更好的进行dom操作,而现在世界上60%的公司也都是在用jQuery,而利用vue可以帮我们做到的:

  1. 项目越来越大,前端工程化越来越明显,项目需要细分到细粒度的模块,vue’的组件系统,可以将一个大型的界面切分成一个一个更小的可控单元
  2. 可变的命令式操作,vue让DOM的更新操作是自动的,状态变化的时候DOM可以自动更新到正确的状态
  3. 做单页应用,需要有一个URL对应到一个应用的状态,vue路由vue-router可以提供路由解决方案
  4. 规模的状态管理,当应用变得很大,多人协作就会涉及多个组件之间的共享、多个组件需要去改动同一份状态,vue状态管理库vuex可以帮助这样大规模应用进行状态管理,让其依然能够高效运行
  5. vue脚手架提供的完整的项目结构,内置了webpack配置,你也可以根据自定义的从npm安装相应的依赖,诸如axios,sass,postcss等

技术选型并不容易,选择适合项目的框架可以事半功倍,时代发展越来越来,业务需求越来越复杂,前端的需求也急速提高,利用前端框架诸如vue,react提供的一套完善的全家桶配合前端构建工具可以使我们变得更简单

vue实践

以前在公司都是用的jQuery,自己学习vue也只是通过业余自学,包括前端构建工具,css预处理器等等,所以做的项目不是很多,也算不上什么经验,来了胜因很幸运,刚到就是一个前端vue实现的单页面放在眼前,要求用jQuery实现,期间只是纯粹的剥离数据和样式,没有对vue进行深入的学习,但是熟悉了vue项目的一些基本结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
.
├── config.js # 项目配置文件
├── build/ # webpack 配置文件
│ └── ...
├── src/
│ ├── main.js # app 入口文件
│ ├── App.vue # app 主组件
│ ├── components/ # ui 组件
│ │ └── ...
│ └── assets/ # 模块静态资源,会被 webpack 打包
│ └── ...
├── static/ # 纯静态资源,打包是直接被复制
├── test/
│ └── unit/ # 单元测试
│ │ ├── specs/ # test spec files
│ │ ├── index.js # 测试入口文件
│ │ └── karma.conf.js # 测试配置文件
│ └── e2e/ # 端到端测试
│ │ ├── specs/ # test spec files
│ │ ├── custom-assertions/ # 端到端的自定义断言
│ │ ├── runner.js # 测试脚本
│ │ └── nightwatch.conf.js # 测试配置文件
├── .babelrc # babel 配置
├── .eslintrc.js # eslint 配置
├── index.html # index.html 模版
└── package.json # 命令和依赖列表

然后开始进行早晚班后台开发,第一次接触这么中型的vue单页面项目,从一开始的不知道如何下手到后来的慢慢熟悉和上手,期间对于vue学习收获了很多,也了解了配合vue一起使用的element-ui组件库,提供了很多诸如table,input,notification等组件

vue用法

你可以在页面上直接<script>引入vue文件

1
<script src="https://unpkg.com/vue"></script>

你也可以直接用vue命令行工具(前提是你熟悉node)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 安装npm
install npm
# 选择淘宝cnpm镜像
$ npm install -g cnpm --registry=https://registry.npm.taobao.org
# 全局安装 vue-cli
$ npm install --global vue-cli
# 选择webpack模板
$ vue init webpack my-project
# 安装依赖
$ cd my-project
$ npm install
# 运行
$ npm run dev
# 打包部署
$ npm run build

vue主要语法包括:

  1. 声明式渲染:双括号进行动态绑定
  2. 指令:v-bind,v-for,v-if等,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM
  3. 组件:组件可以扩展 HTML 元素,封装可重用的代码
  4. vue生命周期:从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程

Vue 实例

在文档中经常会使用 vm 这个变量名表示 Vue 实例,在实例化 Vue 时,需要传入一个选项对象,它可以包含数据(data)、模板(template)、挂载元素(el)、方法(methods)、生命周期钩子(lifecyclehook)等选项

1
2
3
4
5
6
7
8
9
10
11
12
13
var vm = new Vue({
data: { a: 1 },
methods: {
A: function () {

}
},
computed: {
B: function () {

}
}
})
vue生命周期

对于vue生命周期的了解,是你开发vue项目的必经之路,你必须很清晰的知道每一个流程,你的每一个操作,dom会发生什么变化

beforecreate : 可以在这加个loading事件,在加载实例时触发
created : 初始化完成时的事件写在这里,异步请求也适宜在这里调用
mounted : 挂载元素,获取到DOM节点
updated : 如果对数据统一处理,在这里写上相应函数
beforeDestroy : 可以做一个确认停止事件的确认框
nextTick : 更新数据后立即操作dom

更多内容参考=》vue官方文档: https://cn.vuejs.org

vue-router

vue-router是vue的官方路由,若是你想开发一个单页面vue应用,那么这将会是你最好的选择,上手也极其简单

你可以直接在页面里面引入(vue作为大哥肯定是不能少的)

1
2
<script src="/path/to/vue.js"></script>
<script src="/path/to/vue-router.js"></script>

你也可以在npm安装vue-router到项目依赖

1
2
3
4
5
6
7
# 安装 vue-router
npm install vue-router
# 导入vue,vue-router
import Vue from 'vue'
import VueRouter from 'vue-router'
# 显示的使用vue-router
Vue.use(VueRouter)

来一个example看下基本的用法:

html部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>

<div id="app">
<h1>Hello App!</h1>
<p>
<!-- 使用 router-link 组件来导航. -->
<!-- 通过传入 `to` 属性指定链接. -->
<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
</p>
<!-- 路由出口 -->
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>

js部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 0. 如果使用模块化机制编程,導入Vue和VueRouter,要调用 Vue.use(VueRouter)

// 1. 定义(路由)组件。
// 可以从其他文件 import 进来
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }

// 2. 定义路由
// 每个路由应该映射一个组件。 其中"component" 可以是
// 通过 Vue.extend() 创建的组件构造器,
// 或者,只是一个组件配置对象。
// 我们晚点再讨论嵌套路由。
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]

// 3. 创建 router 实例,然后传 `routes` 配置
// 你还可以传别的配置参数, 不过先这么简单着吧。
const router = new VueRouter({
routes // (缩写)相当于 routes: routes
})

// 4. 创建和挂载根实例。
// 记得要通过 router 配置参数注入路由,
// 从而让整个应用都有路由功能
const app = new Vue({
router
}).$mount('#app')

// 现在,应用已经启动了!

套用的vue-router官方的例子,关于vue-router主要的部分无非是:

  1. <router-link> :支持用户在具有路由功能的应用中(点击)导航。 通过 to 属性指定目标地址,默认渲染成带有正确链接的 <a> 标签,可以通过配置 tag 属性生成别的标签.。另外,当目标路由成功激活时,链接元素自动设置一个表示激活的 CSS 类名

  2. <router-view>:渲染路径匹配到的视图组件。<router-view> 渲染的组件还可以内嵌自己的 <router-view>,根据嵌套路径,渲染嵌套组件

  3. 路由信息对象:表示当前激活的路由的状态信息,包含了当前 URL 解析得到的信息,还有 URL 匹配到的 route records(路由记录),属性包括:

    3.1 $route.path: 对应当前路由的路径,总是解析为绝对路径,

    3.2 $route.params: key/value 对象,包含了 动态片段 和 全匹配片段

    3.3 $route.query: key/value 对象,表示 URL 查询参数

    3.4 $route.hash: 当前路由的 hash 值 (带 #)

  4. Router 构造配置: 属性有routes,mode,base等

更多请查阅=》vue-router官方文档: https://router.vuejs.org/zh-cn/

vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化,借鉴了flux,redux等架构思想,对大中型vue项目各个组件间的状态进行管理

你可以直接在页面引入(仍然要先引入vue)

1
2
<script src="/path/to/vue.js"></script>
<script src="/path/to/vuex.js"></script>

仍然,你也可以选择方便的安装依赖到package.json

1
2
3
4
5
6
7
# 安装依赖到项目中
npm install vuex --save
# 页面引入
import Vue from 'vue'
import Vuex from 'vuex'
# 显示使用vuex
Vue.use(Vuex)

vuex代码一撇

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state) {
// 变更状态
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})

vuex主要包括:

  1. store:每一个 Vuex 应用的核心就是 store(仓库),创建一个 store

    store = new Vuex.Store({})

  2. state:state就是Store中包含应用中的状态,获取状态store.state.count

  3. mutations:更改 Vuex 的 store 中的状态的唯一方法是提交 mutation,类似于事件,store.commit("increment")

  4. actions: action 提交的是 mutation,而不是直接变更状态

  5. modules: 可以将store切割成模块也就是module,可以帮助我们更好的分离各个组件间的状态

更多请查阅=》vuex官方文档: https://vuex.vuejs.org/zh-cn/installation.html

element-ui

element-ui是一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的组件库,提供了配套设计资源,使用与vue2.0项目开发,提供了很多有用的组件

页面直接引入

1
2
3
4
<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-default/index.css">
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>

npm安装

1
npm i element-ui -S

如果是通过npm 安装需要注意了,你需要在main.js中引入Element

1
2
3
4
5
# 引入
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-default/index.css'
# 使用
Vue.use(ElementUI)

但是还没完,样式文件还没有引入,你需要单独的引入组件的样式文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# npm 安装 babel-plugin-component
npm install babel-plugin-component -D

# 修改.babelrc
{
"presets": [
["es2015", { "modules": false }]
],
"plugins": [["component", [
{
"libraryName": "element-ui",
"styleLibraryName": "theme-default"
}
]]]
}

然后现在你可以根据官方文档选择你想要的组件进行开发了,若是想单独引入单个组件也是可以的

1
2
3
4
5
6
# 引入button select组件
import { Button, Select } from 'element-ui'

# 别忘了显示使用
Vue.use(Button)
Vue.use(Select)

组件太多,API写的很详细

随意的举个例子

1
2
3
4
5
6
7
8
9
10
11
<!-->
面包屑导航效果如下:
首页/活动管理/活动列表/活动详情
<-->

<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>活动管理</el-breadcrumb-item>
<el-breadcrumb-item>活动列表</el-breadcrumb-item>
<el-breadcrumb-item>活动详情</el-breadcrumb-item>
</el-breadcrumb>

更多请查阅=》element-ui官方文档:http://element.eleme.io/#/zh-CN