• vue项目实战经验汇总


    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 改变文字方向
    https://note.youdao.com/yws/public/resource/9c3b95f76c7c720da259832b7b0e087f/xmlnote/D19A72F2CA8F435C9285D24ADBAD4857/12997
    变为
    img2

    调整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;
         50px;
        position: relative;
        z-index: 1;
    }
    

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

    https://note.youdao.com/yws/public/resource/9c3b95f76c7c720da259832b7b0e087f/xmlnote/F78532DA69D64227BB91A5D7D1B74C8E/13062

    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

    image
    注意环境变量的前缀必须是VUE_APP
    image
    在其他文件中通过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",
      },
    
  • 相关阅读:
    多组件共享-vuex —— 使用vuex 报错 actions should be function or object with ”handler“
    时间复杂度/空间复杂度
    Nodejs学习(三)-安装nodejs supervisor,提高点效率吧。
    Nodejs学习(二)-express生成器
    Nodejs学习(一)-Nodejs和express的安装和配置
    PHP连接MySQL的时候报错SQLSTATE[HY000] [2002] No such file or directory
    phpstorm 16.1 注册码
    Express安装过程
    NodeJs解析web一例
    NodeJs 连接mysql一例。
  • 原文地址:https://www.cnblogs.com/mrwh/p/12327883.html
Copyright © 2020-2023  润新知