项目总结

技巧

  1. 解决回车和失去焦点重复触发函数的问题
  2. 差异可以通过组件传参区分
@keyup.enter.native="$event.target.blur"

2.通过style绑定样式

:style="{ background: card.backColor, borderColor: card.bordColor }"

防抖

// fn 需要处理的函数
// t 时间
function debounce(fn, t=500){
    let timer = null;
    return function(){
      timer&&clearTimeout(timer);
      timer = setTimeout(fn, t)
    }
}

打印

print({ printable: 'print_body', type: 'html', targetStyles: ['*'] })

上传二进制文件

excel导入

// 导入excel表格
beforeFileUpload (files) {
  let fileFormData = new FormData()
  fileFormData.append('file', files, this.files.name)
  console.log(fileFormData)
    //已经在importByExcel设置 headers: { 'Content-Type': 'multipart/form-data'},
  importByExcel(fileFormData).then(res => {
    this.$message.success('导入成功')
  })
  // this.getList() // 刷新列表
  // return false
},

excel导出

本质就是利用a标签下载

// 导出excel表格
    exportExcel () {
      exportByExcel().then(res => {
        const blob = new Blob([res])
        const fileName = '模板.xlsx'
        const elink = document.createElement('a')
        elink.download = fileName
        elink.style.display = 'none'
        elink.href = URL.createObjectURL(blob)
        document.body.appendChild(elink)
        elink.click()
        URL.revokeObjectURL(elink.href) // 释放URL 对象
        document.body.removeChild(elink)
      })
  }

mixin

mixin能够有效的减少多余的代码

数据冲突:合并处理、组件优先级更高

钩子冲突:都被调用,先调用mixin钩子,再调用组件钩子

全局参数

//路由跳转前设置
sessionStorage.setItem("menberid", val.id);
//跳转后获取全局参数
this.menberid = sessionStorage.getItem("menberid"); 

路由跳转

getDetailInfo () {
      this.$router.push({
        name: 'income_detail',
        params: {
          drugType: 0
        }
      })
    }

双向绑定

操作dom,并将数据绑定到实例上

样式修改

document.getElementById('test-id').style.cssText="display:none !important;"

随机字符串

//生成一个36位的随机数
let randomStr = [...'0123456789qwertyuiopasdfghjklzxcvbnm'].reduce((p,c,i,arr)=> p+arr[Math.ceil(Math.random()*35)],'')

sync修饰符

子组件:this.$emit('update:name',paulod)

父组件:<child :name.sync="name"></child>

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>.sync</title>
  </head>
  <body>
    <div id="app">
        父组件传递
      <child :name.sync="name"></child>
      <button type="button" @click="changePropsInFather">
        在父组件中将props值改变为'props'
      </button>
    </div>
    <script src="https://unpkg.com/vue"></script>
    <script>
      // 定义一个子组件
      Vue.component("Child", {
        template: `<h1 @click="changePropsInChild">hello, {{name}}</h1>`,
        props: {
          name: String
        },
        methods: {
          changePropsInChild() {
        let said = 'hello this is child'
        //子组件向父组件传递
           this.$emit('update:name',said)
          }
        }
      });
      // 实例化一个Vue对象
      const app = new Vue({
        el: "#app",
        data() {
          return {
            name: "world"
          };
        },
        methods: {
          changePropsInFather() {
            this.name = "I am from father";
          }
        }
      });
    </script>
  </body>
</html>

pc适配

1、安装插件
npm install postcss-px2rem px2rem-loader --save
2、在根目录src中新建util目录下新建rem.js等比适配文件

--------------------------
-js文件
// rem等比适配配置文件
// 基准大小
const baseSize = 16
// 设置 rem 函数
function setRem () {
  // 当前页面宽度相对于 1920宽的缩放比例,可根据自己需要修改。
  const scale = document.documentElement.clientWidth / 1920
  // 设置页面根节点字体大小(“Math.min(scale, 2)” 指最高放大比例为2,可根据实际业务需求调整)
  document.documentElement.style.fontSize = baseSize * Math.min(scale, 2) + 'px'
}
// 初始化
setRem()
// 改变窗口大小时重新设置 rem
window.onresize = function () {
  setRem()
}
----------------------------
3、mian.js中引入
import './util/rem'
4、到vue.config.js中配置插件
----------------------
-js文件
// 引入等比适配插件
const px2rem = require('postcss-px2rem')
// 配置基本大小
const postcss = px2rem({
  // 基准大小 baseSize,需要和rem.js中相同
  remUnit: 16
})

// 使用等比适配插件
module.exports = {
  lintOnSave: true,
  css: {
    loaderOptions: {
      postcss: {
        plugins: [
          postcss
        ]
      }
    }
  }
}

----------------------

sse基本使用

//接口
import { addRegEvent } from '@api/doctor.inquiry'
//页面初始化时调用接口  
created () {
    this.init()
    //建立sse连接
    let eventSource = new EventSource(addRegEvent + `?token=${util.cookies.get('token')}`)
    //监听状态改变
    eventSource.addEventListener('change',event => (this.init()),false)
  }

BUG

//打印出来的数据与后台传递的数据不一样
//原因:在vue组件传值时,传递的参数由于是引用类型,然后又在父组件中修改了传递参数(引用类型)的数据,所以才导致了这个问题

vue无法热加载问题:css中一个属性

时间

setDate:设置时间

const event = new Date('August 19, 1975 23:15:30');
event.setDate(24);
console.log(event.getDate()); //24

虚拟dom刷新不实时,但是又想操作dom时。可以将id绑定值为id获取元素

插件

dayjs

npm install dayjs --save
import dayjs from 'dayjs'
//获取当前时间
dayjs() 下表为当前日期
let date = new Date()
dayjs(date).format('YYYY-MM-DD dddd HH:mm:ss.SSS A') 格式化时间

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oys6WdYm-1604547262046)(C:\Users\tayy\AppData\Roaming\Typora\typora-user-images\1587863869848.png)]

v-charts

extend的使用

<template>
  <ve-histogram
    :data="chartData"
    :extend="chartExtend">
  </ve-histogram>
</template>

<script>
  export default {
    data () {
      this.chartExtend = {
        series (v) {
          v.forEach(i => {
            i.barWidth = 10
          })
          return v
        },
        tooltip (v) {
          v.trigger = 'none'
          return v
        }
      }
      /* 等同于
        this.chartExtend = {
          series: {
            barWidth: 10
          },
          tooltip: {
            trigger: 'none'
          }
        }
        等同于
        this.chartExtend = {
          'series.0.barWidth': 10,
          'series.1.barWidth': 10,
          'tooltip.trigger': 'none'
        }
      */
      return {
        chartData: {
          columns: ['日期', '成本', '利润'],
          rows: [
            { '日期': '1月1日', '成本': 15, '利润': 12 },
            { '日期': '1月2日', '成本': 12, '利润': 25 },
            { '日期': '1月3日', '成本': 21, '利润': 10 },
            { '日期': '1月4日', '成本': 41, '利润': 32 },
            { '日期': '1月5日', '成本': 31, '利润': 30 },
            { '日期': '1月6日', '成本': 71, '利润': 55 }
          ]
        }
      }
    }
  }
</script>

crypto-js

在request拦截器中使用HMAC-SHA1加密

// 请求拦截器
zyService.interceptors.request.use(config => {
  // 授权码
  const assessKey = 'sCm0fN3P9lw42eTStzC3qA=='
  // 密匙
  const secretKey = '179d5ddb-5a8f-4322-b23a-267f62625a36'
  // 获取时间戳
  let timestamp = new Date().getTime()
  // 获取请求方式,请求接口url
  let { method, url } = config
  let StringToSign = method + '|' + url + '|' + timestamp
  // SHA1加密
  const SHA1Arr = hmacSHA1(StringToSign, secretKey)
  // Base64再次加密
  const Sign = SHA1Arr.toString(crypto.enc.Base64)
  // 请求头授权码
  const Authorization = 'HM ' + assessKey + ':' + Sign + 'lr12'
  console.log(Authorization)
  // get 参数序列化 空格 数组
  if (config.method === 'get') {
    config.paramsSerializer = function (params) {
      return stringify(params, { indices: false })
    }
  }
  config.headers['Content-Type'] = 'application/json; charset=UTF-8'
  config.headers['X-HM-Timestamp'] = timestamp
  config.headers['Authorization'] = Authorization
  // 携带token
  if (config.url.indexOf('/login') === -1) {
    const token = util.cookies.get('token')
    config.headers['token'] = token
  }
  console.log(config.headers)
  // 返回中间件
  return config
},
                                

?.

  1. 安装依赖 npm install @babel/plugin-proposal-optional-chaining --save

  2. 在babel.config.js中 的 plugins中添加 @babel/plugin-proposal-optional-chaining

module.exports = {
  presets: ['@vue/app'],
  plugins: ['@babel/plugin-proposal-optional-chaining']
}

异常打印

打印异常

function errorCreate (msg) {
    //创建一个异常实例
    const err = new Error(msg)  
    //添加到日志
    this.$store.state.dispatch('errorAdd', {type: 'error',err,info: '数据请求异常'})
    //开发环境打印
    if (process.env.NODE_ENV === 'development') console.log(err)
    //界面抛出提示
    this.$message.error(err)
    //控制台抛出移除,【打印err的发生位置】
    throw err
}
errorCreate(123)

编码规范

注释

页面

<!--
    创建人:E00n
    页面标题:医生问诊
    开发者:E00n
-->

函数

/**
* 医生科室列表
* @param null
*/
export function docDeps () {
  return request({
    url: '/v1/doctor/department'
  })
}

/**
* 确认就诊
* @param registerId 挂号id
*/
export function confirmVisit (registerId) {
  return request({
    url: '/v1/doctor/confirmVisit',
    method: 'put',
    data: registerId
  })
}

字符串

静态字符串使用’'单引号,动态使用``反引号

const a = 'foo'
const b = `bar${a}`

对象

对象尽量静态化,不要随意添加属性,添加的话最好使用Object. assign

动态属性尽量在创建时定义好

//bad
const a = {}
a.x = 1
a[getKey('enabled')] = true;
//good
const a = {}
Object.assign(a,{x:1,[getKey('enabled')]:true})
//best
const a ={x:null,[getKey('enabled')]: true}
a.x = 1

vue

目录

api:接口

assets:静态资源

components:常用插件(小型插件)

layout:骨架

libs:架包|引入的工具包

menu:导航菜单

plugin:插件

router:路由

views:试图,页面

App.vue

main.js

vuex

modules:当设置namespaced属性为true时,会开启模块空间

namespaced: true

//state
this.$store.state.模块名.模块属性
//mutations
this.$store.commit('模块名/模块方法','参数')
computed: {
...mapState('taadmin/user', ['info']),
...mapState(['clinicInfo'])w'f
},

element-ui

<el-table
        :data="tempList"
        stripe
        style="width: 100%"
        height="500"
        @expand-change="toggle"
        :row-key="getRowKeys"
        :expand-row-keys="expands"
      >
        <el-table-column
          type="expand"
          label="展开"
          width="60"
        >
          123
        </el-table-column>
</el-table>
//expend只展开一行
//data-表格
  tempList: [],
  getRowKeys (row) { // 行数据的Key
    return row.id
  },
  expands: [] // 通过该属性设置Table目前的展开行,需要设置row-key属性才能使用,该属性为展开行的keys数组


//methods- 切换行
toggle (row, expandedRows) {
  this.expands = []
  if (expandedRows.length > 0 && row) {
    this.expands.push(row.id)
  }
},

中台项目

js-cookie

import Cookie from "js-cookie";

const cookie = {};
//存储cookie
cookie.set = function(name = "default", value = "", setting = {}) {
  var realSetting = {
    expires: 1
  };
  Object.assign(realSetting, setting);
  return Cookie.set(`ta-${name}`, value, realSetting);
};
//拿到cookie
cookie.get = function(name = "default") {
  return Cookie.get(`ta-${name}`);
};
//全部的cookie值
cookie.getAll = function() {
  return Cookie.get();
};
//移除cookie
cookie.remove = function(name = "default") {
  return Cookie.remove(`ta-${name}`);
};

export default cookie;

axios

import axios from "axios";
import { Message } from "element-ui";
import cookie from "./cookie";
import { stringify } from "qs";

// 开发环境显示错误信息
function errorLog(err) {
  if (process.env.NODE_ENV === "development") {
    console.log(err);
    Message({ message: err.message, type: "error", duration: 5 * 1000 });
  }
}
function createService(baseURL = "127.0.0.1") {
  // 创建一个 axios 实例
  const service = axios.create({
    baseURL,
    timeout: 30000 // 请求超时时间
  });

  // 请求拦截器
  service.interceptors.request.use(
    config => {
      // get 参数序列化 空格 数组
      if (config.method === "get") {
        config.paramsSerializer = function(params) {
          return stringify(params, { indices: false });
        };
      }
      config.headers["Content-Type"] = "application/json; charset=UTF-8";
      // 在请求发送之前做一些处理
      if (config.url.indexOf("/login") === -1) {
        config.headers["token"] = cookie.get("token");
      }
      return config;
    },
    error => {
      errorLog(error);
    }
  );

  // 响应拦截器
  service.interceptors.response.use(
    response => {
      // dataAxios 是 axios 返回数据中的 data
      const dataAxios = response.data;
      // 这个状态码是和后端约定的
      const { code } = dataAxios;
      // 根据 code 进行判断
      if (code === undefined || response.config.isOut) {
        return dataAxios;
      } else {
        // 有 code 代表这是一个后端接口 可以进行进一步的判断
        switch (code) {
          case 200:
            return dataAxios.data;
          case 201:
            console.log(dataAxios.message);
            break;
          default:
            console.log(dataAxios.message);
            break;
        }
      }
    },
    error => {
      if (error && error.response) {
        switch (error.response.status) {
          case 400:
            error.message = "请求错误";
            break;
          case 401:
            error.message = "未授权,请登录";
            cookie.remove("token");
            window.location = "/#/login";
            break;
          case 403:
            error.message = "拒绝访问";
            break;
          case 404:
            error.message = "请求地址出错";
            break;
          case 408:
            error.message = "请求超时";
            break;
          case 500:
            error.message = "服务器内部错误";
            break;
          case 501:
            error.message = "服务未实现";
            break;
          case 502:
            error.message = "网关错误";
            break;
          case 503:
            error.message = "服务不可用";
            break;
          case 504:
            error.message = "网关超时";
            break;
          case 505:
            error.message = "HTTP版本不受支持";
            break;
          default:
            break;
        }
      }
      errorLog(error);
      return Promise.reject(error);
    }
  );
  return service;
}
export default createService;

vue.config.js

const path = require("path");
const TerserPlugin = require("terser-webpack-plugin");
const px2rem = require("postcss-px2rem");
const postcss = px2rem({
  // 基准大小 baseSize,需要和rem.js中相同
  remUnit: 16
});
module.exports = {
  publicPath: "./", // 基本路径
  outputDir: "dist", // 输出文件目录
  lintOnSave: false, // eslint-loader 是否在保存的时候检查
  // webpack配置
  configureWebpack: config => {
    if (process.env.NODE_ENV === "production") {
      // 为生产环境修改配置...
      config.mode = "production";
      // 将每个依赖包打包成单独的js文件
      let optimization = {
        runtimeChunk: "single",
        splitChunks: {
          chunks: "all",
          maxInitialRequests: Infinity,
          minSize: 20000,
          cacheGroups: {
            vendor: {
              test: /[\\/]node_modules[\\/]/,
              name(module) {
                // get the name. E.g. node_modules/packageName/not/this/part.js
                // or node_modules/packageName
                const packageName = module.context.match(
                  /[\\/]node_modules[\\/](.*?)([\\/]|$)/
                )[1];
                // npm package names are URL-safe, but some servers don't like @ symbols
                return `npm.${packageName.replace("@", "")}`;
              }
            }
          }
        },
        minimizer: [
          new TerserPlugin({
            cache: true,
            parallel: true,
            sourceMap: true,
            terserOptions: {
              compress: {
                warnings: false,
                drop_console: true, // console
                drop_debugger: false,
                pure_funcs: ["console.log"] // 移除console
              }
            }
          })
        ]
      };
      Object.assign(config, {
        optimization
      });
    } else {
      // 为开发环境修改配置...
      config.mode = "development";
    }
    Object.assign(config, {
      // 开发生产共同配置
      resolve: {
        alias: {
          "@": path.resolve(__dirname, "./src"),
          "@c": path.resolve(__dirname, "./src/components"),
          "@api": path.resolve(__dirname, "./src/api")
        } // 别名配置
      }
    });
  },
  productionSourceMap: true, // 生产环境是否生成 sourceMap 文件
  // css相关配置
  css: {
    sourceMap: false,
    loaderOptions: {
      css: {},
      scss: {},
      postcss: {
        plugins: [postcss]
      }
    },
    requireModuleExtension: false
  },
  parallel: require("os").cpus().length > 1, // 是否为 Babel 或 TypeScript 使用 thread-loader。该选项在系统的 CPU 有多于一个内核时自动启用,仅作用于生产构建。
  pwa: {}, // PWA 插件相关配置
  // webpack-dev-server 相关配置
  devServer: {
    open: process.platform === "darwin",
    host: "0.0.0.0", // 允许外部ip访问
    port: 8022, // 端口
    https: false, // 启用https
    overlay: {
      warnings: true,
      errors: true
    }, // 错误、警告在页面弹出
    proxy: {
      "/api": {
        target: "http://www.baidu.com/api",
        changeOrigin: true, // 允许websockets跨域
        ws: true, //ws跨域
        pathRewrite: {
          "^/api": ""
        }
      }
    } // 代理转发配置,用于调试环境
  },
  // 第三方插件配置
  pluginOptions: {}
};

px2rem

// 基准大小
const baseSize = 16;
// 设置 rem 函数
function setRem() {
  // 当前页面宽度相对于 1920宽的缩放比例,可根据自己需要修改。
  const scale = document.documentElement.clientWidth / 1920;
  // 设置页面根节点字体大小(“Math.min(scale, 2)” 指最高放大比例为2,可根据实际业务需求调整)
  document.documentElement.style.fontSize =
    baseSize * Math.min(scale, 2) + "px";
}
// 初始化
setRem();
// 改变窗口大小时重新设置 rem
window.onresize = function() {
  setRem();
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值