- Vue 动态构建用户界面 渐进式JavaScript 框架
- 双向绑定原理
- vue的原理分析
- vue-cli 脚手架
- vue生命周期
- 双大括号表达式
- 指令一: 强制数据绑定
- 指令二: 绑定事件监听
- class 绑定
- style 绑定
- 条件渲染指令
- v-model
- v-on 绑定事件
- $nextTick
- 组件间通信
- vue-ajax
- Mint UI 组件库
- vue-router
- vuex
- 注册全局组件
- 注册局部组件
- set
- 缓存路由组件对象
- 路由组件懒加载
- 图片懒加载: vue-lazyload
- better-scroll
- less
- Monment
- vue2.0 keep-alive
- vue+mockjs
- vue解决跨域 代理
Vue 动态构建用户界面 渐进式JavaScript 框架
vue 特点
1.遵循MVVM模式
2.编码简洁, 体积小, 运行效率高, 适合移动/PC端开发
3.它本身只关注UI, 可以轻松引入vue插件或其它第三库开发项目
双向绑定原理
vue数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的。
我们已经知道实现数据的双向绑定,首先要对数据进行劫持监听,所以我们需要设置一个监听器Observer,用来监听所有属性。如果属性发上变化了,就需要告诉订阅者Watcher看是否需要更新。因为订阅者是有很多个,所以我们需要有一个消息订阅器Dep来专门收集这些订阅者,然后在监听器Observer和订阅者Watcher之间进行统一管理的。接着,我们还需要有一个指令解析器Compile,对每个节点元素进行扫描和解析,将相关指令(如v-model,v-on)对应初始化成一个订阅者Watcher,并替换模板数据或者绑定相应的函数,此时当订阅者Watcher接收到相应属性的变化,就会执行对应的更新函数,从而更新视图。因此接下去我们执行以下3个步骤,实现数据的双向绑定:
1.实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。
2.实现一个订阅者Watcher,每一个Watcher都绑定一个更新函数,watcher可以收到属性的变化通知并执行相应的函数,从而更新视图。
3.实现一个解析器Compile,可以扫描和解析每个节点的相关指令(v-model,v-on等指令),如果节点存在v-model,v-on等指令,则解析器Compile初始化这类节点的模板数据,使之可以显示在视图上,然后初始化相应的订阅者(Watcher)。
https://www.jianshu.com/p/f194619f6f26
详解
vue的原理分析
数据代理
1)数据代理: 通过一个对象代理对另一个对象(在前一个对象内部)中属性的操作(读/写)
2)vue数据代理: 通过vm对象来代理data对象中所有属性的操作
3)好处: 更方便的操作data中的数据
4)基本实现流程
a.通过Object.defineProperty()给vm添加与data对象的属性对应的属性描述符
b.所有添加的属性都包含getter/setter
c.getter/setter内部去操作data中对应的属性数据
模板解析
模板解析的基本流程
1)将el的所有子节点取出, 添加到一个新建的文档fragment对象中
2)对fragment中的所有层次子节点递归进行编译解析处理
* 对大括号表达式文本节点进行解析
* 对元素节点的指令属性进行解析
* 事件指令解析
* 一般指令解析
3)将解析后的fragment添加到el中显示
模板解析(1): 大括号表达式解析
1)根据正则对象得到匹配出的表达式字符串: 子匹配/RegExp.$1 name
2)从data中取出表达式对应的属性值
3)将属性值设置为文本节点的textContent
模板解析(2): 事件指令解析
1)从指令名中取出事件名
2)根据指令的值(表达式)从methods中得到对应的事件处理函数对象
3)给当前元素节点绑定指定事件名和回调函数的dom事件监听
4)指令解析完后, 移除此指令属性
模板解析(3): 一般指令解析
1)得到指令名和指令值(表达式) text/html/class msg/myClass
2)从data中根据表达式得到对应的值
3)根据指令名确定需要操作元素节点的什么属性
-
v-text—textContent属性
-
v-html—innerHTML属性
-
v-class–className属性
4)将得到的表达式的值设置到对应的属性上
5)移除元素的指令属性
数据绑定
一旦更新了data中的某个属性数据, 所有界面上直接使用或间接使用了此属性的节点都会更新
数据劫持
1)数据劫持是vue中用来实现数据绑定的一种技术
2)基本思想: 通过defineProperty()来监视data中所有属性(任意层次)数据的变化, 一旦变化就去更新界面
四个重要对象
1)Observer
a.用来对data所有属性数据进行劫持的构造函数
b.给data中所有属性重新定义属性描述(get/set)
c.为data中的每个属性创建对应的dep对象
2)Dep(Depend)
a.data中的每个属性(所有层次)都对应一个dep对象
b.创建的时机:
* 在初始化define data中各个属性时创建对应的dep对象 * 在data中的某个属性值被设置为新的对象时c.对象的结构
js
{
id, // 每个dep都有一个唯一的id
subs //包含n个对应watcher的数组(subscribes的简写)
}
d.subs属性说明
* 当watcher被创建时, 内部将当前watcher对象添加到对应的dep对象的subs中
3)Compile
a.用来解析模板页面的对象的构造函数(一个实例)
b.利用compile对象解析模板页面
c.每解析一个表达式(非事件指令)都会创建一个对应的watcher对象, 并建立watcher与dep的关系
d.complie与watcher关系: 一对多的关系
4)Watcher
a.模板中每个非事件指令或表达式都对应一个watcher对象
b.监视当前表达式数据的变化
c.创建的时机: 在初始化编译模板时
d.对象的组成
js
{
vm, //vm对象
exp, //对应指令的表达式
cb, //当表达式所对应的数据发生改变的回调函数
value, //表达式当前的值
depIds //表达式中各级属性所对应的dep对象的集合对象
//属性名为dep的id, 属性值为dep
}
5)总结: dep与watcher的关系: 多对多
a.data中的一个属性对应一个dep, 一个dep中可能包含多个watcher(模板中有几个表达式使用到了同一个属性)
b.模板中一个非事件表达式对应一个watcher, 一个watcher中可能包含多个dep(表达式是多层: a.b)
c.数据绑定使用到2个核心技术
vue-cli 脚手架
npm install -g vue-cli //下载脚手架
vue init webpack vue_demo //创建脚手架 vue_demo
npm run start //开发环境
npm run build //生产环境 生成dist文件夹
npm install -g serve //运行 dist文件
serve dist
vue生命周期
生命周期:Vue 实例从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期,各个阶段有相对应的事件钩子
生命周期钩子函数
注意:
created阶段的ajax请求与mounted请求的区别:前者页面视图未出现,如果请求信息过多,页面会长时间处于白屏状态
mounted 不会承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以用 vm.$nextTick
详情请访问:
https://segmentfault.com/a/1190000014705819
http://web.jobbole.com/94470/
双大括号表达式
语法:
{ { exp } }
功能: 向页面输出数据
可以调用对象的方法
指令一: 强制数据绑定
功能: 指定变化的属性值
完整写法:
v-bind:xxx='yyy' //yyy会作为表达式解析执行
简洁写法:
:xxx='yyy'
指令二: 绑定事件监听
功能: 绑定指定事件名的回调函数
完整写法:
v-on:keyup='xxx'
v-on:keyup='xxx(参数)'
v-on:keyup.enter='xxx'
简洁写法:
@keyup='xxx'
@keyup.enter='xxx'
class 绑定
语法:
:class='xxx'
表达式是字符串:
'classA'
表达式是对象:
{classA:isA, classB: isB}
表达式是数组:
['classA', 'classB']
style 绑定
语法:
:style="{ color: activeColor, fontSize: fontSize + 'px' }"
其中activeColor/fontSize是data属性
条件渲染指令
语法:
<div v-if="bool">study vue</div>
示例:
<div id="demo">
<h2 v-if="ok">表白成功</h2>
<h2 v-else>表白失败</h2>
<h2 v-show="ok">求婚成功</h2>
<h2 v-show="!ok">求婚失败</h2>
<button @click="ok=!ok">切换</button>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: '#demo',
data: {
ok: false
}
})
</script>
v-if是动态的向DOM树内添加或者删除DOM元素;
v-show是通过设置DOM元素的display样式属性控制显隐;
#v-for 列表渲染
遍历数组
<li v-for="(p, index) in persons" :key="index">
{ { index } }--{ { p.name} } -- { { p.age } }
</li>
- 遍历对象
< li v-for="(value, key) in persons">
{ { key } } : { { value } }
< /li>
v-model
双向数据绑定 自动收集数据
v-on 绑定事件
语法:
v-on:xxx="fun"
简写:
@xxx="fun"
$nextTick
语法:
this.$nextTick(() => {})
用法: 界面更新后执行回调函数 示例1:
component组件
mounted () {
this.$store.dispatch('getShopGoods', () => {
this.$nextTick(() => {
this._initScroll()
this._intTops()
})
})
}
// 异步获取商品列表 action
async getShopGoods ({commit},cb) {
const result = await reqShopGoods()
if (result.code === 0) {
const goods = result.data
commit(RECEIVE_GOODS,{goods})
cb && cb()
}
}
通过dispach更新数据的时候可以传函数,在action中commit之后调用此函数,说明是在更新完数据之后才调用的,但是这是界面还没有更新完成,所以用$nextTick,这样界面更新后执行$nextTick里面的回调函数 此时在回调函数中执行的语句才会生效
示例2:
watch: {
// 更新状态数据后, 界面会异步更新
categorys (val) { // 状态数据改变了, 但界面还没有更新
/* setTimeout(() => {
new Swiper('.swiper-container', {
pagination: { // 圆点指示器的容器div
el: '.swiper-pagination'
},
loop: true, // 可以循环轮播
})
}, 100) */
// 回调是在当前数据变化的DOM更新之后自动调用
this.$nextTick(function () {
new Swiper('.swiper-container', {
pagination: { // 圆点指示器的容器div
el: '.swiper-pagination'
},
loop: true, // 可以循环轮播
})
})
}
}
组件间通信
语法:
slot
父组件:<slot name="left"></slot>
子组件:<span class="header_search" slot="left">
示例:
子组件
<template>
<header class="header">
<slot name="left"></slot>
<span class="header_title">
<span class="header_title_text ellipsis"></span>
</span>
<slot name="right"></slot>
</header>
</template>
父组件
<HeaderTop :title="address.name">
<span class="header_search" slot="left">
<i class="iconfont icon-sousuo"></i>
</span>
<span class="header_login" slot="right">
<span class="header_login_text">登录|注册</span>
</span>
</HeaderTop>
props
语法:
<my-component :set-name='setName'>study vue</my-component>
方式一: 只指定名称
props: ['name', 'age', 'setName']
方式二: 指定名称和类型
props: {
name: String,
age: Number,
setNmae: Function
}
方式三: 指定名称/类型/必要性/默认值
props: {
name: {type: String, required: true, default:xxx},
}
注意:
-
此方式用于父组件向子组件传递数据
-
所有标签属性都会成为组件对象的属性, 模板页面可以直接引用
3.问题:
a.如果需要向非子后代传递数据必须多层逐层传递
b.兄弟组件间也不能直接props通信, 必须借助父组件才可以
vue自定义事件
语法: 方式一: 通过v-on绑定
this.$emit('deleteTodo', data) //子组件中
@deleteTodo="deleteTodo" //父组件中 注意:必须写在子组件对应的组件标签上
方式二: 通过$on()
this.$refs.xxx.$on('delete_todo', function (todo) {
this.deleteTodo(todo)
})
注意:
1.此方式只用于子组件向父组件发送消息(数据)
- 隔代组件或兄弟组件间通信此种方式不合适
消息订阅与发布(PubSubJS库)
npm install pubsub-js --save
订阅消息
PubSub.subscribe('msg', function(msg, data){})
发布消息
PubSub.publish('msg', data)
注意:优点: 此方式可实现任意关系组件间通信(数据)
vue-ajax
axios
执行 GET 请求
为给定 ID 的 user 创建请求
axios.get('/user?ID=12345')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
可选地,上面的请求可以这样做
axios.get('/user', {
params: {
ID: 12345
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
执行 POST 请求
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
执行多个并发请求
function getUserAccount() {
return axios.get('/user/12345');
}
function getUserPermissions() {
return axios.get('/user/12345/permissions');
}
axios.all([getUserAccount(), getUserPermissions()])
.then(axios.spread(function (acct, perms) {
// 两个请求现在都执行完成
}));
axios封装
ajax.js
import axios from 'axios'
const baseUrl = ''
// const baseUrl = 'http://localhost:4000'
export default function ajax(url, data={}, type='GET') {
return new Promise(function (resolve, reject) {
let promise
// 执行异步ajax请求的代码
url = baseUrl + url
if(type==='GET') { // 发送GET请求
// 拼请求参数串
// data: {username: tom, password: 123}
// paramStr: username=tom&password=123
let paramStr = ''
Object.keys(data).forEach(key => {
paramStr += key + '=' + data[key] + '&'
})
if(paramStr) {
paramStr = '?' + paramStr.substring(0, paramStr.length-1)
}
// 使用axios发get请求
promise = axios.get(url + paramStr)
} else {// 发送POST请求
// 使用axios发post请求
promise = axios.post(url, data)
}
promise.then(response => {
// 成功了, 调用 resolve
resolve(response.data)
}).catch(error => {
// 失败了, 调用 reject
reject(error)
})
})
}
index.js
定义接口请求函数//获取短信验证码
export const reqSendCode = phone => ajax('/api/sendcode', {phone})
Mint UI 组件库
下载:npm install –save mint-ui
实现按需打包
- 下载
npm install --save-dev babel-plugin-component
2.修改babel配置
"plugins": ["transform-runtime",["component", [
{
"libraryName": "mint-ui",
"style": true
}
]]]
vue-router
下载:
npm install vue-router --save
基本步骤:
1.分析是否需要 在哪需要 创建路由组件,然后创建路由组件
2.将我们创建的一般组件映射映射成路由组件
3.< router-link to=’/msite’/>
< router-view/>
示例:
router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import MSite from '../pages/MSite/MSite.vue'
import Search from '../pages/Search/Search.vue'
import Order from '../pages/Order/Order.vue'
import Profile from '../pages/Profile/Profile.vue'
import Login from '../pages/Login/Login.vue'
import Shop from '../pages/Shop/Shop.vue'
import ShopGoods from '../pages/Shop/ShopGoods/ShopGoods.vue'
import ShopRatings from '../pages/Shop/ShopRatings/ShopRatings.vue'
import ShopInfo from '../pages/Shop/ShopInfo/ShopInfo.vue'
Vue.use(VueRouter)
export default new VueRouter({
// 所有路由
routes: [
{
path: '/msite',
component: MSite,
meta: {
isShow: true
}
},
{
path: '/search',
component: Search,
meta: {
isShow: true
}
},
{
path: '/Order',
component: Order,
meta: {
isShow: true
}
},
{
path: '/profile',
component: Profile,
meta: {
isShow: true
}
},
{
path: '/login',
component: Login
},
{
path: '/shop',
component: Shop,
children: [
{
path: '/shop/goods',
component: ShopGoods
},
{
path: '/shop/ratings',
component: ShopRatings
},
{
path: '/shop/info',
component: ShopInfo
},
{
path: '',
redirect: '/shop/goods'
},
]
},
{
path: '/',
redirect: '/msite'
},
]
})
main.js
import Vue from 'vue'
import {Button} from 'mint-ui'
import App from './App.vue'
import router from './router' // <---
import store from './store'
import Split from './components/Split/Split.vue'
import './mock/mockServer' // 只需要引入即可
Vue.component(Button.name, Button)
Vue.component('Split', Split)
/* eslint-disable no-new */
new Vue({
el: '#app',
render: h => h(App),
router, // <---
store
})
router跳转
1.标签跳转
<router-link to='/msite'/>
<router-view/>
2.js动态跳转及传参
query方式传参和接收参数
传参:
this.$router.push({
path:'/xxx'
query:{
id:id
}
})
接收参数:
this.$route.query.id
params方式传参和接收参数
传参:
this.$router.push({
name: 'dispatch',
params: {
id:id
}
})
接收参数:
this.$route.params.id
注意:params传参,push里面只能是 name:’xxx’,不能是path:’/xxx’,因为params只能用name来引入路由,如果这里写成了path,接收参数页面会是undefined!!!
另外,二者还有点区别,直白的来说query相当于get请求,页面跳转的时候,可以在地址栏看到请求参数,而params相当于post请求,参数不会再地址栏中显示
vuex
概念:对vue应用中多个组件的共享状态进行集中式的管理(读/写)
4部分组成
action
mutations
getters
state
示例:
state.js
export default {
latitude: 40.10038, // 纬度
longitude: 116.36867, // 经度
address: {}, // 地址信息对象
categorys: [], // 分类数组
shops: [], //商家数组
user: {}, // 用户信息对象
goods: [], // 商品列表
ratings: [], // 商家评价列表
info: {}, // 商家信息
cartFoods: [] // 购物项food数组
}
actions.js
import {
RECEIVE_ADDRESS,
RECEIVE_CATEGORYS,
RECEIVE_SHOPS
} from './mutation-types'
import {
reqAddress,
reqFoodTypes,
reqShops
} from '../api'
export default {
// 异步获取地址信息的异步action
async getAddress ({commit, state}) {
const {latitude, longitude} = state
const geohash = `${latitude},${longitude}`
// 发送异步请求, 得到响应数据
const result = await reqAddress(geohash) // {code: 0, data: address}
if(result.code===0) {
// 提交mutation
const address = result.data
commit(RECEIVE_ADDRESS, {address})
}
}
// 同步更新指定food数量
updateFoodCount ({commit}, {isAdd, food}) {
if(isAdd) {
commit(INCREMENT_FOOD_COUNT, {food})
} else {
commit(DECREMENT_FOOD_COUNT, {food})
}
},
// 同步清空购物车
clearCart ({commit}) {
commit(CLEAR_CART)
}
}
mutations.js
import Vue from 'vue'
import {
RECEIVE_ADDRESS,
RECEIVE_CATEGORYS
} from './mutation-types'
export default {
[RECEIVE_ADDRESS] (state, {address}) {
state.address = address
},
[RECEIVE_CATEGORYS] (state, {categorys}) {
state.categorys = categorys
}
}
mutation-types.js
export const RECEIVE_ADDRESS = 'receive_address' // 接收地址信息
export const RECEIVE_CATEGORYS = 'receive_categorys' // 接收分类数组
getters.js
export default {
// 购物车中所有food的数量
totalCount (state) {
return state.cartFoods.reduce((preTotal, food)=> preTotal + food.count, 0)
},
// 购物车中所有food的总价格
totalPrice (state) {
return state.cartFoods.reduce((preTotal, food)=> preTotal + food.count*food.price, 0)
}
}
index.js
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import mutations from './mutations'
import actions from './actions'
import getters from './getters'
Vue.use(Vuex)
export default new Vuex.Store({
state,
mutations,
actions,
getters
})
main.js
import Vue from 'vue'
import {Button} from 'mint-ui'
import App from './App.vue'
import router from './router'
import store from './store' // <-----
import Split from './components/Split/Split.vue'
import './mock/mockServer' // 只需要引入即可
Vue.component(Button.name, Button)
Vue.component('Split', Split)
/* eslint-disable no-new */
new Vue({
el: '#app',
render: h => h(App),
router,
store // <-----
})
获取状态 、 更新状态
方式一
import {mapState, mapGetters, mapActions} from 'vuex'
export default {
computed: {
...mapState(['xxx'],['mmm']),
...mapGetters(['xxx'],['mmm']),
}
methods: {
...mapActions(['xxx'],['mmm'])
}
}
方式二
this.$store.state.xxx
this.$store.getters.xxx
this.$store.dispatch('action名称', data1)
dispatch用法
this.$store.dispatch('allUnionInstitution')
.then(() => { })
.catch(() => { })
注册全局组件
import Split from './components/Split/Split.vue'
Vue.component('Split', Split)
注册局部组件
export default{
components: {
AlertTip
}
}
set
给状态添加属性值
语法:
Vue.set( food, 'count', 1 )
说明: food state里面的属性
'count' 添加属性名
1 添加属性值
缓存路由组件对象
<keep-alive>
<router-view />
</keep-alive>
好处: 复用路由组件对象, 复用路由组件获取的后台数据
路由组件懒加载
src/router/index.js
/*
import goods from 'pages/goods/goods.vue'
import ratings from 'pages/ratings/ratings.vue'
import seller from 'pages/seller/seller.vue'
*/
const goods = () => import('pages/goods/goods.vue')
const ratings = () => import('pages/ratings/ratings.vue')
const seller = () => import('pages/seller/seller.vue')
图片懒加载: vue-lazyload
2)下载包
npm install --save vue-lazyload
使用
//main.js
import VueLazyload from 'vue-lazyload'
import loading from './common/img/loading.gif'
Vue.use(VueLazyload, {
loading
})
//component
<img v-lazy="food.image">
better-scroll
中文地址:
http://ustbhuangyi.github.io/better-scroll/doc/zh-hans/#
下载
npm install better-scroll --save //生产环境依赖
示例:
<template>
<div class="wrapper">
<ul class="content">
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
</ul>
</div>
</template>
<script>
import BScroll from 'better-scroll'
export default {
name: 'App',
mounted () {
new BScroll('.wrapper',{
bounce: true,
momentumLimitDistance: 1,
scrollY: true,
scrollbar: {
fade: true,
interactive: false
},
mouseWheel: true,
})
}
}
</script>
<style scoped lang="less">
li{
height:400px;
background: #ff0;
}
.wrapper{
height:100%;
}
</style>
less
下载:
npm install less less-loader --save-dev
安装成功后,打开 build/webpack.base.conf.js ,在 module.exports = 的对象的 module.rules 后面添加一段:
module.exports = {
// 此处省略无数行,已有的的其他的内容
module: {
rules: [
// 此处省略无数行,已有的的其他的规则
{
test: /\.less$/,
loader: "style-loader!css-loader!less-loader",
}
]
}
}
最后,在代码中的 style 标签中 加上 lang=”less” 属性即可
<style scoped lang="less">
</style>
Monment
下载:
npm install moment --save # npm
示例:
watch:{
flashSaleIndexVO(val){
let time = val.remainTime
const interval=setInterval(()=>{
time-=1000
const x= moment.duration(time); //得到的是对象
this.timer = x
if(time<=0){
clearInterval(interval)
}
},1000)
}
},
示例:自定义事件过滤器
import Vue from 'vue'
import moment from 'moment'
// 定义一个自定义过滤器
Vue.filter('date-format', function (value, format='YYYY-MM-DD HH:mm:ss') {
return moment(value).format(format)
})
< div>{ { flashSaleIndexVO.nextStartTime | date-format('HH:mm:ss') } } </div>
vue2.0 keep-alive
1.基本用法
vue2.0提供了一个keep-alive组件用来缓存组件,避免多次加载相应的组件,减少性能消耗
<keep-alive>
<component>
<!-- 组件将被缓存 -->
</component>
</keep-alive
有时候 可能需要缓存整个站点的所有页面,而页面一般一进去都要触发请求的
在使用keep-alive的情况下
<keep-alive><router-view></router-view></keep-alive>
将首次触发请求写在created钩子函数中,就能实现缓存,
比如列表页,去了详情页 回来,还是在原来的页面
2.缓存部分页面或者组件
(1)使用router.meta属性
// 这是目前用的比较多的方式
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view
router设置
...
routes: [
{ path: '/', redirect: '/index', component: Index, mate: { keepAlive: true }},
{
path: '/common',
component: TestParent,
children: [
{ path: '/test2', component: Test2, mate: { keepAlive: true } }
]
}
....
// 表示index和test2都使用keep-alive
(2).使用新增属性inlcude/exclude
2.1.0后提供了include/exclude两个属性 可以针对性缓存相应的组件
<!-- comma-delimited string -->
<keep-alive include="a,b">
<component :is="view"></component>
</keep-alive>
<!-- regex (use v-bind) -->
<keep-alive :include="/a|b/">
<component :is="view"></component>
</keep-alive
注意:这种方法都是预先知道组件的名称的
(2)动态判断
<keep-alive :include="includedComponents">
<router-view></router-view>
</keep-alive
vue实现前进刷新,后退不刷新
const router = new Router({
routes: [
{
path: '/',
redirect: '/login'
},
{
path: '/login',
component: Login,
meta: {
keepAlive: true
}
},
{
path: '/login/server',
component: ServerList,
meta: {
keepAlive: true
}
},
{
path: '/login/server/main',
component: Main,
meta: {
keepAlive: true
}
}
]
})
由于这三个界面path的层级不同,我就能通过beforeEach这个钩子判断出什么时候是后退了。在后退时将from路由的keepAlive置为false,to路由的keepAlive置为ture。
router.beforeEach((to, from, next) => {
const toDepth = to.path.split('/').length
const fromDepth = from.path.split('/').length
if (toDepth < fromDepth) {
console.log('后退。。。')
from.meta.keepAlive = false
to.meta.keepAlive = true
}
next()
})
最后需要缓存的界面用keep-alive包起来,就能实现时前进刷新,后退时不刷新的效果了。
<keep-alive>
<router-view v-if="$route.meta.keepAlive">
<!-- 这里是会被缓存的视图组件 -->
</router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive">
<!-- 这里是不被缓存的视图组件 -->
</router-view>
vue+mockjs
下载
npm install mockjs
网址
http://mockjs.com/
mockServer.js
示例:
/*
使用mockjs提供mock数据接口
*/
import Mock from 'mockjs'
import data from './msite.json'
Mock.mock('/headCateList', {code:0, data: data.headCateList})
Mock.mock('/focusList', {code:0, data: data.focusList})
Mock.mock('/tagList', {code:0, data: data.tagList})
在main.js入口文件里面引入mockServer.js就可以了(import ‘../src/mock/mockServer’)
vue解决跨域 代理
config/index.js
proxyTable: {
'/api': { // 匹配所有以 '/api'开头的请求路径
target: 'http://localhost:4000', // 代理目标的基础路径
changeOrigin: true, // 支持跨域
pathRewrite: {// 重写路径: 去掉路径中开头的'/api'
'^/api': ''
}
}
}
api/index.js
export const reqFoodTypes = () => ajax('/api/index_category')