目录
一、Vue.js入门
-
MVVM架构
-
传统的MVC架构:
-
View:获取Model的数据,当用户触发事件响应时,触发控制器
-
Controller:控制器接收View的事件,并修改Model中的数据
-
Model:由控制器负责修改Model数据,Model数据发生改变时,修改View表现层
-
-
MVP架构:
-
View:呈现视图
-
ViewModel:负责View和Model的数据双向绑定
-
Model:数据
-
-
-
Vue.js定位:View相当于DOM,Vue.js是ViewModel层,用于数据绑定
-
Vue.js定位:
-
数据驱动
-
组件化
-
-
数据绑定和计算属性
-
数据绑定
-
vue插值语法:
-
文本内容:{{msg}}
-
-
-
{{user.name}}
{{user.phone}}
```
2. 指令
- v-if、v-text、v-html、v-bind、v-on
-
使用指令的方式不需要使用插值
-
v-bind可以使用:缩写、v-on可以使用@绑定
-
-
计算属性
-
原因:模板不应该过于复杂,如果数据过于复杂,需要使用计算属性
-
computed属性包含:用户获取计算属性的方法,带有get和set方法。
边长是:{{a}}
面积是:{{s}}
``` -
-
条件渲染
-
v-if和v-show
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../node_modules/vue/dist/vue.js" type="text/javascript"></script> </head> <body> <div id="app"> <div id="isshow" v-if="isshow">是否显示</div> <div id="isnotshow" v-else="isshow">是否显示2</div> <div id="isshow2" v-show="isshow">是否显示</div> <div id="isshow3" v-show="notshow">是否显示</div> </div> </body> <script> var vm = new Vue({ el: "#app", data:{ isshow: true, notshow: false } }) </script> </html>
-
条件渲染的注意事项
-
v-show不支持<template>
-
v-else必须紧跟在v-if/v-show指令后面
-
条件组合下不能使用v-else
-
-
两种渲染的比较:v-if会清除DOM元素,v-show不会清除DOM元素
-
-
列表渲染及其注意事项
-
数组元素遍历
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../node_modules/vue/dist/vue.js" type="text/javascript"></script> </head> <body> <div id="app"> <template id="num" v-for="n in num"> <span class="item">{{n}}</span> </template> <template id="num" v-for="(item,index) in num"> <span class="item">{{index}}</span> <span class="item">{{item}}</span> </template> </div> </body> <script> var vm = new Vue({ el: "#app", data:{ num:['one','two','three','four','five'] } }) </script> </html>
-
可以使用template元素进行遍历。
-
可以获取当前的item的序号和内容,过去的$index用法已经被移除。
-
-
对象属性遍历
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../node_modules/vue/dist/vue.js" type="text/javascript"></script> </head> <body> <div id="app"> <div id="people" v-for="(value,key,index) in person"> <span>{{index}}</span> <span>{{key}}</span> <span>{{value}}</span> </div> </div> </body> <script> var vm = new Vue({ el: "#app", data:{ person:{ name: 'zhangsan', age: '10', sex: 'boy' } } }) </script> </html>
-
整数次重复
<div id="people" v-for="n in 5">{{n}}</div>
-
过滤和排序
-
使用filterBy与orderBy
-
使用计算属性
-
-
数据检测变化及注意事项
-
当数组发生变化时,应当通过重新赋值的方式,来刷新数据。
-
vm.items.$set(index,newItem),vm.item.$remove(existingItem),是vue.js提供的快捷的方法,可以直接对数组赋值。
-
使用track-by可以复用已有的对象。
-
-
二、Vue.js类、样式、表单和事件绑定
-
类与样式绑定
-
使用v-bind绑定类与样式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../node_modules/vue/dist/vue.js" type="text/javascript"></script> <style> #box{ width: 100px; height: 100px; } .redbox{background-color: red;} .bluebox{ background-color: blue; } </style> </head> <body> <div id="app"> <div id="box" :class="bluebox" :style="redbox"></div> </div> </body> <script> var vm = new Vue({ el: "#app", data:{ bluebox: 'bluebox', redbox: 'background-color: red;' } }) </script> </html>
-
这种方式不能直接指定css中的类
-
如果希望直接使用css中的类,需要使用表达式
<div id="box" :class="{ bluebox:true }"></div>
-
-
vue.js对类与样式绑定增强
-
绑定多个类
<div id="box" :class="{bluebox:true, redborder:true}"></div>
-
如果需要对多个类绑定,可以使用数组语法
<div id="box" :class="[ isActive ? bluebox : '' ]"></div>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../node_modules/vue/dist/vue.js" type="text/javascript"></script> <style> #box{ width: 100px; height: 100px; } .bluebox{ background-color: blue; } .redborder{ border: 1px solid red; } </style> </head> <body> <div id="app"> <div id="box" :class="bluebox"></div> </div> </body> <script> var vm = new Vue({ el: "#app", data:{ bluebox: ['bluebox','redborder'] } }) </script> </html>
通过对vue对象的修改,可以实时同步到样式。
-
-
-
表单控件绑定
-
使用v-model实现双向绑定
-
Text数据双向绑定
-
Checkbox数据双向绑定
-
Radio数据双向绑定
-
Select数据双向绑定
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../node_modules/vue/dist/vue.js" type="text/javascript"></script> </head> <body> <div id="app"> <input type="text" v-model="user.name"> <input type="number" v-model="user.age"> <input type="checkbox" name="sex" v-model="user.like"> <input type="checkbox" name="sex" v-model="user.hoby" value="1"> <input type="checkbox" name="sex" v-model="user.hoby" value="2"> <input type="checkbox" name="sex" v-model="user.hoby" value="3"> <input type="radio" value="boy" v-model="user.sex" name="sex" selected>boy <input type="radio" value="girl" v-model="user.sex" name="sex">girl<br> <select v-model="user.myselect"> <option>A</option> <option>B</option> <option>C</option> </select> <div>{{user.name}}</div> <div>{{user.age}}</div> <div>{{user.like}}</div> <div>{{user.hoby}}</div> <div>{{user.sex}}</div> <div>{{user.myselect}}</div> </div> </body> <script> var vm = new Vue({ el: "#app", data:{ user: { name: 'zhangsan', age: 18, like: true, hoby:[], sex: 'boy', myselect: 'A' } } }) </script> </html>
-
-
-
事件绑定与处理:事件绑定通过v-on,可以使用简单符号@
-
watch的使用:具体查看文档
三、Vue.js组件开发
-
组件的注册和使用
-
Vue扩展实例选项对象会覆盖预设实例选项
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../node_modules/vue/dist/vue.js" type="text/javascript"></script> </head> <body> <div id="app"> </div> </body> <script> var myVue = Vue.extend({ data:function(){ return{ msg: 'Hello,Vue js', i: 1, obj:{ a: 1, b: 2 } } }, method:{ add: function () { this.i++ } }, template: '<div><div id="newMsg">{{msg}}</div><div id="i">{{i}}</div><div id="obj">{{obj}}</div></div>' }) var vm1 = new myVue({ data:{ newMsg: 'Amazing Vue.js', i: 100, obj:{ b: 99, c: 3, d: 4 } }, method: { add: function () { this.i += 0.5 }, add2: function () { this.i += 2 } } }) vm1.$mount('#app') </script> </html>
template模板可以替换app,但是需要注意的是,template下面只能有一个子项。
-
组件的全局注册于局部注册
// 注册全局组件 Vue.component('myvue',myVue) // 注册局部组件 new Vue({ el: 'body', components:{ 'myvue': myVue } })
-
全局注册组件和局部注册组件只需要传入一个
-
注意,组件的名字必须是全小写字母
-
组件语法糖
// 注册全局组件 Vue.component('myvue',{ data: function () { return{ msg: 'Hello MyVue' } }, template: '<div><div id="newMsg">{{msg}}</div></div>' }) // 注册局部组件 new Vue({ el: '#app' })
只需要传入一个对象,Vue可以帮助我们调用extend方法快速创建组件。
-
使用井号选择子
<div id="myvue-component"> <div id="newMsg">{{msg}}</div> </div> <script> // 注册全局组件 Vue.component('myvue',{ data: function () { return{ msg: 'Hello MyVue' } }, template: '#myvue-component' }) // 注册局部组件 new Vue({ el: '#app' }) </script>
-
-
-
组件模板注意事项
-
模板必须要插入到正确的位置,不能插入到select、tabel等元素内。
-
在模板中如果要使用v-show,只能使用v-show='!condition'。
-
当组件中存在多个顶级元素,成为片段元素,v-show不起作用。
-
如果在模板中使用v-if,页面是先被下载,后被移除到DOM树中。对于普通图片:
<style> [v-cloak]{ display: none; } </style> <div id="myvue-component"> <img src="" alt="" v-cloak> </div>
对于视频,可以设置:
<style> [v-cloak]{ display: none; } </style> <div id="myvue-component"> <img src="" alt="" v-cloak> </div>
-
-
使用props出传递数据
-
span内部不能设置数据的预设值
-
数据必须要被设置,否则使用到的数据就不会被显示
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../node_modules/vue/dist/vue.js" type="text/javascript"></script> </head> <body> <div id="app"> <child message="Hello World"></child> </div> </body> <script> // 注册全局组件 Vue.component('child',{ props:[ 'message' ], template: '<span>{{message}}</span>' }) // 注册局部组件 new Vue({ el: '#app' }) </script> </html>
-
自定义属性的校验
<child :name="sname"></child> new Vue({ el: '#app', data: { sname: 'zhangsan' } })
可以使用静态属性,也可以使用v-bind,将属性绑定在父组件中。
-
如何v-for和v-bind共同使用,可以将属性绑定到重复的组件中。
<child v-for="iname in names" :name="iname"></child> new Vue({ el: '#app', data: { names:[ 'zhangsan', 'lisi', 'wangwu' ] } })
-
Prop验证
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>组件</title> </head> <body> <div id="app"> <mycomponent :name="people.name" :extends_string="people.extends_string"></mycomponent> <mycomponent :name="people.name" :extends_string="people.extends_string"></mycomponent> </div> <template id="tp"> <div> <div><input type="text" v-model="name"></div> <div><input type="text" v-model="age"></div> <div>{{name}}</div> <div>{{age}}</div> <div>{{friends}}</div> <div>{{extends_string | json}}</div> <input type="button" @click="onClickButton" value="ClickMe"> <input type="button" @click="onClickButton2" value="ClickMe"> </div> </template> <script src="node_modules/vue/dist/vue.js" type="text/javascript"></script> <script> var mycomponent = Vue.extend({ template: '#tp', props:{ name:{ type: String, default: '请输入姓名', required: true }, age:{ type: Number, // twoWay: true, validator: function (value) { return value>0&&value<200 }, // // 转换函数 // coerce: function (value) { // return Number(value) // } }, friends:{ type: Array, default: function () { return ['Cherry','Tom'] } }, extends_string:{ type: Object } }, methods:{ onClickButton(){ this.age = Number(this.age) + 1 }, onClickButton2(){ console.log(this.extends_string) this.$set(this.extends_string, this.age, String('Name'+this.age)); } } }) var vm = new Vue({ el: '#app', data:{ people:{ name: 'zhangsan', age: 18, friends:['Cherry'], extends_string:{ } } }, components: { mycomponent: mycomponent } }) </script> </body> </html>
type可以是下面原生构造器
type 可以是下面原生构造器:
-
String
-
Number
-
Boolean
-
Function
-
Object
-
Array
-
-
数据一般只能修改数据到子控件,而不能让子控件修改父控件的数据。
-
Object类型是通用的,而其他类型并不能在子组件之间通用。
-
-
父子组件通信
-
子组件可通过this.$parent访问父组件
-
跟实例的后代都可以通过this.$root访问根节点
-
父组件有一个数组this.$children访问所有子组件
-
自定义事件
-
$on 监听事件
-
$emit触发事件
-
$dispatch派发事件,事件沿着父链冒泡
-
$broadcash广播事件,事件向下传递给后台
-
-
使用v-ref:ref-id为子组件指定一个索引
-
在父组件中使用this.$ref.refId引用子组件
-
v-ref和v-for一起使用时,ref是一个数组或对象,包含所有子组件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>组件</title> </head> <body> <div id="app"> <div id="parent">{{msg}}</div> <mycomponent @click-msg="onClickChild"></mycomponent> </div> <template id="tp"> <div> <input type="button" value="Click Me" @click="emit"> </div> </template> <script src="node_modules/vue/dist/vue.js" type="text/javascript"></script> <script> var mycomponent = Vue.extend({ template: '#tp', props:{ }, methods:{ emit: function () { this.$emit('click-msg','You Click Me') } } }) var vm = new Vue({ el: '#app', data:{ msg: '' }, components: { mycomponent: mycomponent }, methods: { onClickChild: function (value) { this.msg = value } } }) </script> </body> </html>
-
-
使用slot分发内容
-
使用插槽可以实现控件之间的嵌套
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>组件</title> <style> .box{ width: 100px; height: 100px; background-color: coral; border: 1px solid black; float: left; } </style> </head> <body> <div id="app"> <div id="parent">{{msg}}</div> <mycomponent> <div class="box">Box</div> <div class="box" slot="name1">Box3</div> <div class="box" slot="name1">Box4</div> <div class="box" slot="name2">Box5</div> <div class="box">Box2</div> </mycomponent> </div> <template id="tp"> <div> <slot></slot> <slot name="name2"></slot> <slot name="name1"></slot> </div> </template> <script src="node_modules/vue/dist/vue.js" type="text/javascript"></script> <script> var mycomponent = Vue.extend({ template: '#tp', }) var vm = new Vue({ el: '#app', data:{ msg: '' }, components: { mycomponent: mycomponent } }) </script> </body> </html>
-
父组件中指定同名插槽,子组件会将其合并
-
-
动态组件
-
动态组件的使用
-
将多个组件使用同一个挂载点
-
将动态的组件名绑定到:is=""属性上,组件名为<component></component>
-
-
keep-alive特性
-
通常被切换的属性会被卸载,如果不希望被卸载,可以使用<component keep-alive></component>特殊属性
-
-
activate钩子
可以是单个回调函数,也可以是数组,接收钩子done,仅当组件初始化或切换时被调用,不适用于手工方法插入。
-
transition-mode
-
需要引入<link rel="stylesheet" href="../css/vue-animate.min.css">
-
<component :transition="fade" :transition-mode="in-out"></component>
-
动画效果有
-
fade:没有效果
-
bounce:弹跳
-
rotate:旋转
-
slideDown:上下平移淡出
-
zoom:左右平移淡出
-
-
这个动画在最新的版本已经不再适用,甚至变得更加复杂,具体的改变请参考官方文档。
-
-
-
组件开发的注意事项
-
适用webpack对单文件组件进行打包
-
webpack简介
-
打包js
webpack entry.js -o bundle.js
当js文件出现相互引用时:
文件结构:
/index.html
/entry.js
/content.js
entry.js
document.write(require('./content.js'))
content.js
module.exports = 'content.js说webpack看行'
-
打包CSS
-
打包CSS必须要在本地安装css-loader、style-loader,并且需要使用package.json配置好。
-
只能使用配置文件
const path = require('path'); module.exports = { entry: './entry.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'bundle.js' }, module: { rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] } ] }, mode: 'development' };
新的版本和旧的版本配置文件不兼容。
-
-
打包html
{ test: /\.html$/, use: ['html-loader'] }
注意,所有引入的地方都必须要使用相对路径的全写,当前路径以"./"开头,否则就不会被识别。
-
打包jpg
{ test: /\.jpg$/, use: ['url-loader'] }
-
打包其它内容
-
-
单文件组件规范
单文件组件分为三个功能块。
-
支持特性
-
ES2015和Bable
-
CSS作用域
-
PostCSS和Autoprefix
-
热加载
-
-
打包工作流程
-
区分开发和生产环境:
process.env.NODE_ENV!='production'
-
-
四、vue-router开发SPA应用
-
vue-router基本用法
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title> </head> <body> <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> </body> <script src="./node_modules/vue/dist/vue.js"></script> <script src="./node_modules/vue-router/dist/vue-router.js"></script> <template id="foo"> <div>foo</div> </template> <template id="bar"> <div>bar</div> </template> <script> const router = new VueRouter({ routes: [ { path: '/foo', component: { template: '#foo' } }, { path: '/bar', component: { template: '#bar' } } ] }) const app = new Vue({ router }).$mount('#app') </script> </html>
-
注意new Vue({})中只能写一个对象,不能使用任何key去指定这个对象!
-
命名路由
-
为路由添加name属性,跳转的时候可以通过名字跳转。
-
-
嵌套路由
-
可以为路由模板中定义子路由
-
定义父级路由的时候也需要指定子路由的name和子路由的模板
-
-
-
vue-router路由对象与路径匹配
-
路由对象属性、自定义字段
-
组件激活的时候,使用ready(){}事件,可以再组件激活的时候打印东西。
-
在组件内打印:this.$route,可以访问自己组建的路由对象。
-
path:路径
-
params:路由动态片段和全匹配片段的对象
-
query:参数(同GET请求参数)
-
matched:当前匹配中的所有片段和参数
-
name:路由所在的名字
-
可以为路由增加自定义字段
-
-
动态匹配
-
路由的名字并不确定
1. 修改动态匹配的名字 'news/:newsId/:opt':{} 2. 为路由增加参数 'params:{newsId:123,opt:'edit'}' 3. 子组件中打印参数 '{{this.$route.params}}'
-
-
全字段匹配
-
全匹配中很多使用path的方式
1. 修改全匹配的名字 'news:/*board' 2. 修改path path = 'news/pop' 3. 打印参数 '{{this.$route.params}}',结果=pop
-
全匹配同样可以使用多个参数
-
-
-
-
vue-router路由配置项
-
通过路由配置自定义路由行为
-
在初始化路由的时候,可以通过使用不同的参数来进行控制。
var router = new VueRouter({ linkActiveClass: 'current' });
-
主要的配置如下:
参数 默认值 功能描述 hashbang true 所有的路径都会以#!开头,浏览器会将URL设置为example.com/#!/foo history false 使用HTML5 history模式 abstract false 使用一个不依赖浏览器的历史虚拟管理,主要用于非Web应用。 root null 自定义根路径 linkActiveClass v-link-active 为当前元素增加样式 saveScrollPosition false 当浏览器有“前进”、“后退”导航是,并且history为true,可以回滚到历史。 transitionOnLoad false 是否启用<router-view></router-view>切换效果 suppressTransitionError false 切换中如果出现错误,是否中止当前行为 -
使用history时,浏览器会请求服务器,这时服务器并没有此文件,因此需要将具体的文件映射到具体的路由上。
-
如果希望使用history模式,请阅读官网。
-
-
-
五、vuex应用状态管理
-
大型应用中状态管理痛点及使用动态容器实现状态管理
-
在多组件的应用中,组件之间的状态的统一可以使用vuex来存储。
-
-
State和Getters
-
先使用vue-cli初始化项目
vue init webpack sample
-
创建store.js
-
当前的项目目录结构是
/src
/src/vuex
/src/vuex/store.js
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const store = new Vuex.Store({ state: { count: 0 } })
-
在Vue组件中,读取State中的值,有三种方法
-
直接在store中读取
store.js
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const store = new Vuex.Store({ state: { icount: 0, iname: 'zhangsan', iage: 18 } }) export default store
App.vue
<script> import Hello from './Hello' //导入store import store from './vuex/store' export default { name: 'App', components:{ Hello }, mounted(){ console.log('get state from store:',store.state) } } </script>
-
小插曲(禁用ESLint)
rules: [ ...(config.dev.useEslint ? [ // createLintingRule() ] : []),
-
-
通过全局注册store读取
import store from './vuex/store' new Vue({ el: '#app', components: { App }, template: '<App/>', store })
之后可以再任何地方获取store
mounted(){ console.log('get state from store:',this.$store.state) }
-
通过getters获取
store.js
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const store = new Vuex.Store({ state: { ipeople:{ iname: 'zhangan', iage: 18 } }, getters: { doneTodos: state => { return JSON.stringify(state.ipeople) } } }) export default store
之后就可以通过getters获取
mounted(){ console.log('get state from store:', this.$store.getters.doneTodos) }
-
-
-
-
Mutations
-
作为一个事件系统,包括:事件名和回调函数。
-
通过发出事件,修改store中的内容
-
Mutations只支持同步修改,如果希望使用异步修改,需要使用Actions
-
-
Actions
-
vuex action和mutation热重载
-
-
vuex中间件
-
vuex严格模式与表单处理
六、在线机票预订SPA实战需求说明
七、项目构建与规划
-
使用vue-cli搭建项目框架
-
安装:npm i vue-cli -g
-
创建项目:vue init webpack project-name
-
安装项目:npm install安装完成之后,会在8080端口启动一个服务,可以再8080端口中查看网页。
-
-
路由、状态管理及其组件切分
-
通过webpack项目了解路由、状态管理和组件之间的关系。
-