2019-08-25 | UNLOCK

Vue中的小技巧

一、 js适配经验:

在写代码的时候,很有可能写到这种代码:

1
[1,2,3,4,5].includes(1)

或者是使用promise等es6的方法,但是我们的需求是在Android4.4上面完美运行。这样就会出现includes is not undefied等错误提示。我们可以通过webpack的插件来解决,具体的使用方法:

1
2
3
4
5
6
7
8
9
import "babel-polyfill"
import es6Promise from 'es6-promise'
es6Promise.polyfill()
require('es6-promise').polyfill()

// webpack配置文件处
entry: {
app: ['babel-polyfill', './src/main.js']
},

二、 全局定义

当我们写了很多库的时候,我们引入页面可能会变成这样:

1
2
3
4
5
6
7
// vue 1
import utils from "library"
// vue 2
import utils from "library"
...
// vue n
import utils from "library"

可以这样处理

1
2
3
4
5
6
import Vue from 'vue'
import http from "http/http"
Vue.prototype.$okhttp = http

// use
this.$okhttp

这样会节省很多没有必要的代码量

三、 自定义目录

在写代码的时候,很多时候都存在这种情况 :

1
2
import component1 from "../../../../component"
import component2 from "../../../../../component"

这样写的缺陷是一旦某个目录发生变化就会导致引入错误。可以通过webpack路径解决

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
module.exports = {
context: path.resolve(__dirname, '../'),
entry: {
app: ['babel-polyfill', './src/main.js']
},
output: {},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
'components': resolve('src/components'),
'pages': resolve('src/pages')
}
},
module: {
},
node: {
},
plugins: [],
}

在resolve->alias里面可以配置绝对相对路径,在使用的时候

1
2
import component1 from "pages/component"
import component2 from "pages/component"

四、 路由懒加载

官方文档里面定义路由的时候都有两步:

1
2
3
4
5
6
7
8
9
10
11
12
13
import Vue from 'vue'
import Router from 'vue-router'
import xxx from 'xxx'
Vue.use(Router)

const router = new Router({
routes: [
{
path: '/',
component: xxx,
}
]
})

在做大型项目的时候 很可能定义很多很多个路由,那样页面就会写的特别多。此时懒加载就会解决这个问题

1
2
3
4
5
6
7
8
9
10
11
12
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)

const router = new Router({
routes: [
{
path: '/',
component: () => import("xxx")
}
]
})

五、 样式污染和样式覆盖的问题

在我们新建vue的时候,经常会看到scoped

1
2
<style scoped>
</style>

如果我们去掉scoped的时候会发现,在本vue项目内定义的css属性会影响到其他vue页面的css属性。这个就很坑了。所以,我们在使用的时候一定要用scoped

但是在实际的开发中,也会遇到这么个问题。比如elementUI](http://element-cn.eleme.io/#/zh-CN/component/changelog),虽然里面的资源库很强大,但是里面的视图不能完全符合策划的需求,此时就需要进行微调。

1
2
3
4
5
6
7
<style lang="stylus" scoped>
.custom-dialog
.el-dialog__header
padding 0
.el-dialog__body
padding 0
</style>

如果此时我们加上scoped标签的话,我们发现并没有效果,发现去掉scoped才会起作用。

六、 mock、mock

很多情况下,后台还没有搭建完成之前。可能前端没办法进行数据的接入。这种情况可能是一个大问题,这样会严重拖慢项目开发,此时就需要mock
首先在webpack.dev.conf.js里面配置express,

1
2
3
4
5
const express = require('express')
const app = express()
const appData = require('../static/data/user.json')
const apiRouter = express.Router()
app.use('/api',apiRouter)

然后将接口通过devServer发布出去:

1
2
3
4
5
6
7
 before(app) {
app.get('/api/user',(req, res) => {
res.json({
data: appData
})
})
}

使用的时候就直接打开http://localhost:8080/api/user,就可以了。

六、 代理解决跨域

有些时候,在进行本地开发的时候,可能会遇到跨域的问题。为了解决这个问题呢?主要有两种方法:
1、 服务器设置
服务端设置很简单,就是将本地开发的东西加上“Access-Control-Allow-Origin”, “*”,或者是直接将本地开发的ip直接设置成白名单,这样就可以了.
2、 本地代理
首先引入

1
npm install http-proxy-middleware --save

然后在index.js的标签下proxyTable使用

1
2
3
4
5
6
7
'/lesson': {
target: 'http://xxx/v2/webapi/lesson', // 代理的网址
changeOrigin: true, // 允许跨域
pathRewrite: {
'^/lesson': '/'
}
}

使用的时候,就直接使用

1
2
3
4
5
6
7
8
9
10
11
12
axios({
method: 'get',
url:'/lesson' ,
params: qs.stringify(data)
}).then(function (res) {
if (res) {
//...
}
});
}).catch(function (error) {
console.error(error);
})

七、 页面统一判断

在开发中经常会遇到权限判断的问题,我们又不可能在每一个页面的生命周期中去判断一下,可以这样处理:

1
2
3
router.beforeEach((to, from, next) => {
myAccess.checkhaveAccess(to.path) === true ? next() : next('/forbid')
})

八、 事件的传递:

一般来说事件的传递有很多种,比如父子之间传递数据就可以直接用props,和emit来做关联。
父组件给子组件传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 父组件
<parent>
<child :datas="content"></child>
</parent>

data(){
return {
content:'sichaoyun'
};
}

// 子组件

props:["datas"];
// 或者是
props: {
datas: String
}

子组件给父组件传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 子组件
<template>
<div @click="open"></div>
</template>

methods: {
open() {
this.$emit('showbox','the msg'); //触发showbox方法,'the msg'为向父组件传递的数据
}
}
// 父组件
<child @showbox="toshow" :msg="msg"></child> //监听子组件触发的showbox事件,然后调用toshow方法

methods: {
toshow(msg) {
this.msg = msg;
}
}

兄弟组件之间的传递一般有几种方式:
1、 注册全局事件
2、 vuex
3、 localstorage

使用全局事件则代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let vm = new Vue(); //创建实例

<div @click="ge"></div>
methods: {
ge() {
vm.$emit('click',data); //触发事件
}
}

<div></div>
created() {
vm.$on('click', (arg) => {
});
}

九、 列表渲染

v-for循环绑定model:

这个是我在一个微信公众号上面看到的写法,很新颖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 数据    
data() {
return{
obj: {
ob: "OB",
koro1: "Koro1"
},
model: {
ob: "默认ob",
koro1: "默认koro1"
}
}
},
// html模板
<div v-for="(value,key) in obj">
<input type="text" v-model="model[key]">
</div>
// input就跟数据绑定在一起了,那两个默认数据也会在input中显示

v-if尽量不要与v-for在同一节点使用:

v-for 的优先级比 v-if 更高,如果它们处于同一节点的话,那么每一个循环都会运行一遍v-if。

如果想根据循环中的每一项的数据来判断是否渲染,可以这么做:

1
2
3
<li v-for="index in datas" v-if="Object.is(index,0)">
{{ index }}
</li>

如果你想要根据某些条件跳过循环,而又跟将要渲染的每一项数据没有关系的话,可以将v-if放在v-for的父节点:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 根据elseData是否为true 来判断是否渲染,跟每个元素没有关系    
<ul v-if="condition">
<li v-for="index in datas">
{{ index }}
</li>
</ul>
// 数组是否有数据 跟每个元素没有关系
<ul v-if="datas.length">
<li v-for="index in datas">
{{ index }}
</li>
</ul>
<p v-else>没有更多数据</p>

十、 深度watch与watch立即触发回调

watch有两个可选参数
选项:deep
在选项参数中指定 deep: true,可以监听对象中属性的变化。
选项:immediate
在选项参数中指定 immediate: true, 将立即以表达式的当前值触发回调,也就是默认触发一次。

十一、 路由的项目启动页和404页面

1
2
3
4
5
6
7
8
9
10
11
12
export default new Router({
routes: [
{
path: '/', // 项目启动页
redirect:'/login' // 重定向到下方声明的路由
},
{
path: '*', // 404 页面
component: () => import('./notfind')
},
]
})

比如你的域名为:www.baidu.com

项目启动页指的是: 当你进入www.baidu.com,会自动跳转到login登录页。

404页面指的是: 当进入一个没有 声明/没有匹配 的路由页面时就会跳转到404页面。

比如进入www.baidu.com/testRouter,就会自动跳转到notFind页面。

当你没有声明一个404页面,进入www.baidu.com/testRouter,显示的页面是一片空白。

Vue

评论加载中