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项目实战经验汇总的更多相关文章

  1. webpack+vue项目实战(四,前端与后端的数据交互和前端展示数据)

    地址:https://segmentfault.com/a/1190000010063757 1.前言 今天要做的,就是在上一篇文章的基础上,进行功能页面的开发.简单点说呢,就是与后端的数据交互和怎么 ...

  2. Visual Studio 2015开发Qt项目实战经验分享(附项目示例源码)

    Visual Studio 2015开发Qt项目实战经验分享(附项目示例源码)    转 https://blog.csdn.net/lhl1124281072/article/details/800 ...

  3. vue项目实战, webpack 配置流程记录

    vue项目实战记录,地址在这 购物车单界面 npm install npm run dev 跑起来可以看到界面效果 这里简单记录一下webpack的编译流程 入口 package.json " ...

  4. vue项目实战

    本篇文章主要介绍了vue的环境配置,vue项目的目录结构以及在开发vue项目中问题的一些解决方案. 环境配置及目录结构 1.安装node.js(http://www.runoob.com/nodejs ...

  5. Spring Boot +Vue 项目实战笔记(一):使用 CLI 搭建 Vue.js 项目

    前言 从这篇文章开始,就进入真正的实践了. 在前端项目开发中,我们可以根据实际情况不同程度地使用 Vue.利用 Vue CLI(或写成 vue-cli,即 Vue 脚手架)搭建出来的项目,是最能体现 ...

  6. 给缺少Python项目实战经验的人

    我们在学习过程中最容易犯的一个错误就是:看的多动手的少,特别是对于一些项目的开发学习就更少了! 没有一个完整的项目开发过程,是不会对整个开发流程以及理论知识有牢固的认知的,对于怎样将所学的理论知识应用 ...

  7. Vue 项目实战系列 (一)

    最近一直在学习Vue,基本的文档看完后就需要进行具体的项目进行练手了,本系列文章主要是将我学习过程记录下来,和大家一起学习交流. 我在git上找到了一个淘票票的Vue项目,项目地址: https:// ...

  8. vue项目实战总结

    马上过年了,最近工作不太忙,再加上本人最近比较懒,毫无斗志,不愿学习新东西,或许是要过年的缘故(感觉像是在找接口). 就把前一段时间做过的vue项目,进行一次完整的总结. 这次算是详细总结,会从项目的 ...

  9. node vue 项目部署问题汇总

    场景:vue-router为history模式,不带项目名访问的部署,如果资源是用相对路径加载,则资源匹配路径不对 一.带项目名称访问,如部署到tomcat服务上 webpack:  build/ut ...

随机推荐

  1. 海思dv300cv500交叉编译webrtc

    感谢声网提供的webrtc国内源码镜像. 首先要安装好海思编译工具链和git. 先替换一下webrtc代码的仓库网址路径 git config --global user.email "10 ...

  2. Java面向对象之异常详解

    目录 Java面向对象之异常[一] Java面向对象之异常[二] 捕获异常的规则 访问异常信息 异常对方法重写的影响 finally详解 Java面向对象之异常[一] Java面向对象之异常[二] 往 ...

  3. VScode(一):C/C++ & MinGW & Code Runner

    目录 1 VScode配置安装 2 MinGW配置安装 2.1 MinGW下载安装 2.2 MinGW环境配置 3 VScode编译C/C++ 3.1 扩展插件安装 3.2 项目配置 3.2.1 配置 ...

  4. ArcGIS Desktop 10.1 下载地址及破解

    ArcGIS Desktop 10.1 正式版请到这里下载 http://pan.baidu.com/share/link?shareid=27476&uk=3608003693 正式版破解方 ...

  5. 输入n个字符串,找出最长最短字符串(若有个数相同的,都打印出来)

    首先,要求找到最长最短字符串,我们应该用数组将其存起来,输入的个数是不固定的,我们就可以用Scanner获取要输入的个数,最终找到的个数也不固定,我们可以封装两个方法,并且返回值类型为数组. 我遇到的 ...

  6. Python学习中的“按位取反”笔记总结

    | 疑惑 最近在学习Python的过程中了解到位运算符,但对于按位取反有点迷糊,就比如说~9(按位取反)之后的结果是-10,为什么不是6呢?所以下面就来看看为什么不是6,正确结果是如何计算出来的呢? ...

  7. zm吃包子

    [题目背景]: zm 喜欢上了吃包子. [题面描述]: zm 每天都要去买包子,但是为了减肥,zm 设置了一系列规则来控制他每天买包子的数量. 他随机了 n 个特殊字符串,然后用 n 个字符串来衡量接 ...

  8. linux入门系列7--管道符、重定向、环境变量

    前面文章我们学习了linux基础命令,如果将不同命令组合使用则可以成倍提高工作效率.本文将学习重定向.管道符.通配符.转义符.以及重要的环境变量相关知识,为后面的shell编程打下基础. 一.IO重定 ...

  9. THUWC2020 自闭记

    DAY 1 报道 领胸牌和-围巾-! 发现我和 \(ssf\) 小姐姐一个考场. 合影+开幕式 宾馆睡了一觉-睡上午觉真的舒服. 合影时在c位! 开幕式.比上次夏令营不知道好到哪里去了,讲话都挺有意思 ...

  10. git使用的常见命令汇总

    git的简单介绍 git是分布式版本控制工具 git 的基本操作指令 git init 初始化git仓库 git add 文件名 git add . 把文件 添加到 git 暂存区中 git stat ...