事件分发

  • 事件分发 vm.$emit 和监听 vm.$on 必须绑定在同一个 vm 上
  • 创建一个 eventHub.js 文件如下:

    1
    2
    3
    4
    5
    import Vue from "vue";
    // 用来存放分发的事件$emit,$on
    export default new Vue();
    // export let eventHub = new Vue();
    // 使用上面这种写法在import时需要加{}:import { eventHub } from '@/common/js/eventHub.js';
  • 使用 eventHub.$emit(‘fun1’,e)来分发事件,使用 eventHub.$on(‘fun1’,fun2)来监听事件

过渡动画 JavaScript 钩子:

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
32
33
<div id="demo">
<button v-on:click="show = !show">
Toggle
</button>
<transition name="fade" @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter">
<p v-if="show">hello</p>
</transition>
<hr>
<pre v-text="log.join('\n')"></pre>
</div>

new Vue({
el: '#demo',
data: {
show: false,
log: [],
},
methods: {
beforeEnter() {
this.log.push('before-enter')
},
enter(el, done) {
this.log.push('enter')
setTimeout(_ => {
this.log.push('setTimeout')
done()
}, 2000)
},
afterEnter() {
this.log.push('after-enter')
}
}
})

当 afterEnter 立即执行时,可以试着将 v-show 改为 v-if(某些时候会起作用,afterEnter 会变为动画结束后执行)

基于 vue-cli 脚手架搭建的工程如果 css 中的相对路径引用找不到,需要修改 build->untils.js 文件中的

1
2
3
4
5
6
7
8
9
if (options.extract) {
return ExtractTextPlugin.extract({
use: loaders,
publicPath: "../../", // 这边修改路径
fallback: "vue-style-loader"
});
} else {
return ["vue-style-loader"].concat(loaders);
}

混入

混入 (mixins) 是一种分发 Vue 组件中可复用功能的非常灵活的方式。混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项。

定义:

1
2
3
4
5
6
7
8
9
10
11
export const tableObj = {
data() {
return {};
},
methods: {
mockData() {}
},
mounted() {
this.mockData();
}
};

使用:(定于中的变量,方法都可以在引用的文件中使用,相当于在 b 文件中引用了 a 文件定义的变量)

1
2
3
4
import { tableObj } from "src/mixin";
export default {
mixins: [tableObj]
};

路由变化页面数据不刷新问题

出现这种情况是因为依赖路由的 params 参数获取写在 created 生命周期里面,因为相同路由二次甚至多次加载的关系没有达到监听,退出页面再进入另一个文章页面并不会运行 created 组件生命周期,导致文章数据还是第一次进入的数据

解决方法:watch 监听路由是否变化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
watch: {
// 方法1
'$route' (to, from) {
// 监听路由是否变化
if(this.$route.params.articleId){
// 判断条件1 判断传递值的变化
//获取文章数据
}
}
// 方法2
'$route'(to, from) {
if (to.path == "/page") {
// 判断条件2 监听路由名 监听你从什么路由跳转过来的
this.message = this.$route.query.msg
}
}
}

异步回调函数中使用 this 无法指向 vue 实例对象

1
2
3
4
5
6
7
8
9
10
// setTimeout/setInterval ajax Promise等等
data(){
return{ ... }
},
methods (){
setTimeout(function () {
// 其它几种情况相同console.log(this);
// 此时this指向并不是vue实例 导致操作的一些ma'f
},1000);
}

解决方案 变量赋值和箭头函数

var 和 let 的区别

1
2
3
4
5
6
7
8
9
10
// 使用变量访问this实例
let self = this;
setTimeout(function() {
console.log(self);
// 使用self变量访问this实例
}, 1000);
// 箭头函数访问this实例 因为箭头函数本身没有绑定
this.setTimeout(() => {
console.log(this);
}, 500);

setInterval 路由跳转继续运行并没有及时进行销毁

比如一些弹幕,走马灯文字,这类需要定时调用的,路由跳转之后,因为组件已经销毁了,但是 setInterval 还没有销毁,还在继续后台调用,控制台会不断报错,如果运算量大的话,无法及时清除,会导致严重的页面卡顿。

解决办法:在组件生命周期 beforeDestroy 停止 setInterval

1
2
3
4
5
// 组件销毁前执行的钩子函数,跟其他生命周期钩子函数的用法相同。
beforeDestroy() {
// 我通常是把setInterval()定时器赋值给this实例,然后就可以像下面这么停止。
clearInterval(this.intervalId);
}

vue 滚动行为用法,进入路由需要滚动到浏览器底部 头部等等

使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样。 vue-router 能做到,而且更好,它让你可以自定义路由切换时页面如何滚动。

注意: 这个功能只在支持 history.pushState 的浏览器中可用。

路由设置如下: 详情猛戳

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const router = new VueRouter({  
mode: 'history',
scrollBehavior (to, from, savedPosition) {
if (savedPosition) {
//如果savedPosition存在,滚动条会自动跳到记录的值的地方
return savedPosition
} else {
return {
x: 0,
y: 0
}
// savedPosition也是一个记录x轴和y轴位置的对象
}
},
routes: [...]
})

实现 vue 路由拦截浏览器的需求,进行一系列操作 草稿保存等等

场景:

为了防止用户失误点错关闭按钮等等,导致没有保存已输入的信息(关键信息)。

用法:

1
2
3
4
5
6
7
8
9
10
11
12
// 在路由组件中:

...

beforeRouteLeave (to, from, next) {
if(用户已经输入信息){
// 出现弹窗提醒保存草稿,或者自动后台为其保存
} else {
next(true);
// 用户离开
}
}

还有 beforeEach、beforeRouteUpdate 这些生命周期函数 详情猛戳

v-once 只渲染元素和组件一次,优化更新渲染性能

v-once 这个指令相信大家用的很少,不过个人感觉还是挺实用的!

只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。

这个就不举例子了 直接猛戳这 v-once

vue 本地代理配置 解决跨域问题,仅限于开发环境

这个本地代理用来解决开发环境下的跨域问题,跨域可谓老生常谈的问题了,proxy 在 vue 中配置代理非常简单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 比方说你要访问 http://192.168.1.xxx:8888/backEnd/paper 这个接口
// 配置 config.js 下面 proxyTable 对象
proxyTable: {
'/backEnd':{
target:'http://192.168.3.200:8888',
// 目标接口域名有端口可以把端口也写上
// 或者prot本地起服务端口与服务端统一
changeOrigin:true,
}
},
// 发送request请求
axios.get('/backEnd/page').then((res) => { // 按代理配置 匹配到/backEnd就代理到目标target地址
console.log(res)
// 数据完全拿得到 配置成功
this.newsList = res.data
}, (err) => {
console.log(err)
})

本地开发 没有任何问题 部署服务器 就 404 啊这些问题

由于前端路由缘故,单页面应用应该放到 nginx 或者 apache、tomcat 等 web 代理服务器中,千万不要直接访问 index.html,同时要根据自己服务器的项目路径更改 react 或 vue 的路由地址

注意点

  1. vue-router 的 history 模式
  2. 服务 nginx 配置

Vuex + axios 发送请求

安装其他插件的时候,可以直接在 main.js 中引入并 Vue.use(),但是 axios 并不能 use,只能每个需要发送请求的组件中即时引入
为了解决这个问题,有两种开发思路,一是在引入 axios 之后,修改原型链,二是结合 Vuex,封装一个 aciton。具体的实施请往下看~

方案一:改写原型链

首先在 main.js 中引入 axios

1
import axios from "axios";

这时候如果在其它的组件中,是无法使用 axios 命令的。但如果将 axios 改写为 Vue 的原型属性,就能解决这个问题

1
Vue.prototype.$ajax = axios;

在 main.js 中添加了这两行代码之后,就能直接在组件的 methods 中使用 $ajax 命令

1
2
3
4
5
6
7
8
9
10
11
methods: {
submitForm () {
this.$ajax({
method: 'post',
url: '/user',
data: {
name: 'wise',
info: 'wrong'
}
})
}

方案二:在 Vuex 中封装

之前的文章中用到过 Vuex 的 mutations,从结果上看,mutations 类似于事件,用于提交 Vuex 中的状态 state
action 和 mutations 也很类似,主要的区别在于,action 可以包含异步操作,而且可以通过 action 来提交 mutations
另外还有一个重要的区别:
mutations 有一个固有参数 state,接收的是 Vuex 中的 state 对象
action 也有一个固有参数 context,但是 context 是 state 的父级,包含 state、getters

Vuex 的仓库是 store.js,将 axios 引入,并在 action 添加新的方法

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
32
// store.js
import Vue from "Vue";
import Vuex from "vuex";

// 引入 axios
import axios from "axios";

Vue.use(Vuex);

const store = new Vuex.Store({
// 定义状态
state: {
test01: {
name: "Wise Wrong"
},
test02: {
tell: "12312345678"
}
},
actions: {
// 封装一个 ajax 方法
saveForm(context) {
axios({
method: "post",
url: "/user",
data: context.state.test02
});
}
}
});

export default store;

注意:即使已经在 main.js 中引入了 axios,并改写了原型链,也无法在 store.js 中直接使用 $ajax 命令
换言之,这两种方案是相互独立的

参数可以通过调用的时候用变量传递

在组件中发送请求的时候,需要使用 this.$store.dispatch 来分发

1
2
3
4
5
methods: {
submitForm () {
this.$store.dispatch('saveForm')
}
}

submitForm 是绑定在组件上的一个方法,将触发 saveForm,从而通过 axios 向服务器发送请求

后续增加的 key 视图更新问题

1
2
3
4
5
6
7
8
9
var vm = new Vue({
data:{
a:1
}
})
// `vm.a` 是响应的
vm.b = 2
// `vm.b` 是非响应的
// 因为vm.b是后续新增的key