vue项目实战经验汇总

vue

目录

  • 1.vue框架使用注意事项和经验
    • 1.1 解决Vue动态路由参数变化,页面数据不更新
    • 1.2 vue组件里定时器销毁问题
    • 1.3 vue实现按需加载组件的两种方式
    • 1.4 组件之间,父子组件之间的通信方案
    • 1.5 vue中 $event 的用法--获取当前父元素,子元素,兄弟元素
    • 1.6 vue常用工具函数总结
    • 1.7 axios二次封装http请求
  • 2.elementui组件修改经验总结
    • 2.1 element-ui 中步骤条的深度使用
    • 2.2 v-loading框中的提示文字换行
    • 2.3 路由菜单项双击控制台报错
  • 3.Vue项目配置
    • 3.1 Vue-cli3 配置开发、生产和测试环境
    • 3.2开发环境中代理的切换配置

1.vue框架使用注意事项和经验

本文主要总结了在开发vue项目中的一些实践经验和踩过的一些坑,后续会接着更新,便于后期复盘,希望也对你有所帮助

1.1 解决Vue动态路由参数变化,页面数据不更新

问题描述:

遇到动态路由如:/page/:id

从/page/1 切换到 /page/2 发现页面组件没有更新

解决方式:

增加一个不同:key值,这样vue就会识别这是不同的了。

<router-view :key="key"></router-view>

...

computed:{

key(){

return this.$route.path + Math.random();

}

}

1.2 vue组件里定时器销毁问题

问题描述:

在a页面写一个定时器,每秒钟打印一次,然后跳转到b页面,此时可以看到,定时器依然在执行。

推荐的解决方式:

通过$once这个事件侦听器器在定义完定时器之后的位置来清除定时器。

const timer = setInterval(() => {

// 定时器操作

}, 1000)

// 通过$once来监听定时器,在beforeDestroy钩子可以被清除。

this.$once(\'hook:beforeDestroy\', () => {

clearInterval(timer);

})

1.3 vue实现按需加载组件的两种方式

1.使用resolve => require([\'./ComponentA\'], resolve),方法如下:

const ComponentA = resolve => require([\'./ComponentA\'], resolve)

  1. 使用 () => import(), 具体代码如下:

const ComponentA = () => import(\'./ComponentA\')

1.4 组件之间,父子组件之间的通信方案

组件之间的通信方案:

  • 通过事件总线(bus),即通过发布订阅的方式
  • vuex
  • 父子组件:
  • 父组件通过prop向自组件传递数据
  • 子组件绑定自定义事件,通过this.$emit(event,params) 来调用自定义事件
  • 使用vue提供的$parent/$children & $refs方法来通信
  • provide/inject
  • 深层次组件间的通信 $attrs, $listeners

实现细节可参考:https://m.jb51.net/article/167304.htm

1.5 vue中 $event 的用法--获取当前父元素,子元素,兄弟元素

<button @click = “fun($event)”>点击</button>

...

methods: {

fun(e) {

// e.target 是你当前点击的元素

// e.currentTarget 是你绑定事件的元素

#获得点击元素的前一个元素

e.currentTarget.previousElementSibling.innerHTML

#获得点击元素的第一个子元素

e.currentTarget.firstElementChild

# 获得点击元素的下一个元素

e.currentTarget.nextElementSibling

# 获得点击元素中id为string的元素

e.currentTarget.getElementById("string")

# 获得点击元素的string属性

e.currentTarget.getAttributeNode(\'string\')

# 获得点击元素的父级元素

e.currentTarget.parentElement

# 获得点击元素的前一个元素的第一个子元素的HTML值

e.currentTarget.previousElementSibling.firstElementChild.innerHTML

}

},

1.6 vue常用工具函数总结

/*

日期相关 dateFormater:格式化时间

timestampToTime

* */

function dateFormater(formater, t){

let date = t ? new Date(t) : new Date(),

Y = date.getFullYear() + \'\',

M = date.getMonth() + 1,

D = date.getDate(),

H = date.getHours(),

m = date.getMinutes(),

s = date.getSeconds();

return formater.replace(/YYYY|yyyy/g,Y)

.replace(/YY|yy/g,Y.substr(2,2))

.replace(/MM/g,(M<10?\'0\':\'\') + M)

.replace(/DD/g,(D<10?\'0\':\'\') + D)

.replace(/HH|hh/g,(H<10?\'0\':\'\') + H)

.replace(/mm/g,(m<10?\'0\':\'\') + m)

.replace(/ss/g,(s<10?\'0\':\'\') + s)

}

// dateFormater(\'YYYY-MM-DD HH:mm\', 1580787420000)//==> "2020-02-04 11:37"

// dateFormater(\'YYYYMMDDHHmm\', new Date()) //==> 201906261830

/*

获取Url参数,返回一个对象

* */

function GetUrlParam(){

let url = document.location.toString();

let arrObj = url.split("?");

let params = Object.create(null)

if (arrObj.length > 1){

arrObj = arrObj[1].split("&");

arrObj.forEach(item=>{

item = item.split("=");

params[item[0]] = item[1]

})

}

return params;

}

// ?a=1&b=2&c=3 ==> {a: "1", b: "2", c: "3"}

//toFullScreen:全屏

function toFullScreen(){

let elem = document.body;

elem.webkitRequestFullScreen

? elem.webkitRequestFullScreen()

: elem.mozRequestFullScreen

? elem.mozRequestFullScreen()

: elem.msRequestFullscreen

? elem.msRequestFullscreen()

: elem.requestFullScreen

? elem.requestFullScreen()

: alert("浏览器不支持全屏");

}

//exitFullscreen:退出全屏

function exitFullscreen(){

let elem = parent.document;

elem.webkitCancelFullScreen

? elem.webkitCancelFullScreen()

: elem.mozCancelFullScreen

? elem.mozCancelFullScreen()

: elem.cancelFullScreen

? elem.cancelFullScreen()

: elem.msExitFullscreen

? elem.msExitFullscreen()

: elem.exitFullscreen

? elem.exitFullscreen()

: alert("切换失败,可尝试Esc退出");

}

1.7 axios二次封装http请求

import axios from \'axios\'

import router from \'@/router\'

import {removeSessionStorage} from \'./storage\';

import Vue from \'vue\'

import { Message } from \'element-ui\' // 引用element-ui的加载和消息提示组件

// 请求超时时间配置

axios.defaults.timeout = 30000;

// api地址配置

axios.defaults.baseURL = "";

// console.log(process.env.VUE_APP_BASE_API)

Vue.prototype.$http = axios

// 在全局请求和响应拦截器中添加请求状态

let loading = null

// 请求拦截器

axios.interceptors.request.use(

config => {

config.headers = {

\'Content-Type\': \'application/json\'

};

// loading = Loading.service({ text: \'拼命加载中\' })

let token = sessionStorage.getItem(\'-_token_-\');

if (token) {

config.headers[\'token\'] = token;

}

return config

},

error => {

return Promise.reject(error)

}

)

// 响应拦截器

axios.interceptors.response.use(

response => {

if (loading) {

loading.close()

}

//console.log(response)

const code = response.status

if ((code >= 200 && code < 300) || code === 304) {

let errorCode = response.data.errCode;

if(errorCode===\'000000\'){

return Promise.resolve(response.data)

}else {

if (errorCode === \'SYS0404\') {

router.push({

name: \'error\',

params: {

isTimeout: false,

path: router.currentRoute.path,

desc: \'您请求的资源找不到(错误码:404) \',

},

});

} else if (errorCode === \'SYS0401\') {

removeSessionStorage(\'-_token_-\');

router.replace({

path: \'/login\',

query: {

redirect: router.currentRoute.fullPath

}

});

}

// Message.error(response.data.message)

return Promise.resolve(response.data)

}

// return Promise.resolve(response.data)

} else {

return Promise.reject(response)

}

},

error => {

if (loading) {

loading.close();

}

console.log(error);

if (error.response) {

switch (error.response.status) {

case 401:

case 403:

// 返回401 清除token信息并跳转到登陆页面

removeSessionStorage(\'-_token_-\');

router.replace({

path: \'/login\',

query: {

redirect: router.currentRoute.fullPath

}

});

break;

case 404:

Message.error(\'网络请求不存在\');

console.log(\'错误码:404 路由跳转 currentRoute %o \', router.currentRoute.path);

router.push({

name: \'error\',

params: {

isTimeout: false,

path: router.currentRoute.path,

desc: \'您请求的资源找不到(错误码:404) \',

},

});

break;

case 502:

router.push({

name: \'error\',

params: {

isTimeout: false,

path: router.currentRoute.path,

desc: \'网关错误(错误码:502),请联系系统管理员 \',

},

});

break;

default:

Message.error(error.response.data.message ||\'系统出错,请联系系统管理员(错误码:\'+error.response.status+\')!\');

}

} else {

let controlParam = {

desc: \'\',

path: router.currentRoute.path,

isTimeout: false,

};

// 请求超时或者网络有问题

if (error.message.includes(\'timeout\')) {

Message.error(\'请求超时!请检查网络是否正常\');

controlParam.desc = \'网络断开,请检查您的网络 \';

controlParam.isTimeout = true;

} else {

Message.error(\'请求失败,请检查网络是否已连接\');

controlParam.desc = \'页面加载失败 \';

}

router.push({

name: \'error\',

params: controlParam,

});

}

return Promise.reject(error);

}

);

2.elementui组件修改经验总结

2.1 element-ui 中步骤条的深度使用

2.1.1element-UI的操作步骤steps每一项添加事件,比如click,hover

<el-steps :space="200" :active="1" finish-status="success">

<el-step @click.native="on_click(1)" title="已完成"></el-step>

<el-step @click.native="on_click(2)" title="进行中"></el-step>

<el-step @click.native="on_click(3)" title="步骤 3"></el-step>

</el-steps>

2.1.2 具体业务交互

https://blog.csdn.net/weixin_40098371/article/details/88027949

2.1.3 改变文字方向


变为

调整css,设置magin和background

.el-step__main {

white-space: normal;

text-align: left;

margin-top: -31px;

margin-left: 25px;

}

}

i

.el-step__title {

font-size: 16px;

line-height: 38px;

background: #FFF;

width: 50px;

position: relative;

z-index: 1;

}

2.2 v-loading框中的提示文字换行

2.3 路由菜单项双击控制台报错

//解决菜单双击报错

const originalPush = VueRouter.prototype.push

VueRouter.prototype.push = function push(location) {

return originalPush.call(this, location).catch(err => err)

}

3.Vue项目配置

3.1 Vue-cli3 配置开发、生产和测试环境

  • 创建开发环境变量 .env.development
  • 创建生产环境变量 .env.production
  • 创建测试环境变量 .env.test


注意环境变量的前缀必须是VUE_APP


在其他文件中通过process.env.VUE_APP_BASE_API来访问,例如在接口文件代码中

import axios from \'axios\'

import router from \'@/router\'

// 请求超时时间配置

axios.defaults.timeout = 30000;

// api地址配置

axios.defaults.baseURL = "process.env.VUE_APP_BASE_API";

对应的package.json配置为

"scripts": {

"serve": "vue-cli-service serve --mode development",

"build": "vue-cli-service build --mode production",

"test": "vue-cli-service build --mode test",

},

3.2开发环境中代理的切换配置

为了应对这样的跨域场景,在代码开发时,devServer要代理到本地后端,测试时,又要去修改代理到测试环境,上线后,调试新问题有可能代理到线上环境

对vue.config.js的进行配置

const Timestamp = new Date().getTime();  //当前时间为了防止打包缓存不刷新,所以给每个js文件都加一个时间戳

const proxyTargetMap = {

prod: \'https://xxx.xxx.com/\',

dev: \'http://192.168.200.230:6379\',

test: \'http://test.xxx.com\',

local: \'http://localhost:8080/\'

}

let proxyTarget = proxyTargetMap[process.env.API_TYPE] || proxyTargetMap.local

module.exports = {

publicPath: process.env.NODE_ENV === \'production\' ? \'/\' : \'/\',

outputDir: \'dist\',

assetsDir: \'static\',

lintOnSave: false, // 是否开启eslint保存检测

productionSourceMap: false, // 是否在构建生产包时生成sourcdeMap

// 调整内部的 webpack 配置。

// 查阅 https://github.com/vuejs/vue-docs-zh-cn/blob/master/vue-cli/webpack.md

chainWebpack: () => { },

//configureWebpack 这部分打包文件添加时间戳,防止缓存不更新

configureWebpack: {

output: { // 输出重构 打包编译后的 文件名称 【模块名称.版本号.时间戳】

filename: `[name].${process.env.VUE_APP_Version}.${Timestamp}.js`,

chunkFilename: `[name].${process.env.VUE_APP_Version}.${Timestamp}.js`

},

},

devServer : {

proxy: {

\'/api\' : {

target: proxyTarget,

changeOrigin: true,

pathRewrite: {

\'^/api\' : \'\'

}

}

}

}

};

对应的package.json配置为

"scripts": {

"serve": "vue-cli-service serve --mode development",

+ "serve:dev": "cross-env API_TYPE=dev vue-cli-service serve --mode development",

+ "serve:test": "cross-env API_TYPE=test vue-cli-service serve --mode development",

"build": "vue-cli-service build --mode production",

"test": "vue-cli-service build --mode test",

},

以上是 vue项目实战经验汇总 的全部内容, 来源链接: utcz.com/z/374719.html

回到顶部