chp项目总结

123 阅读3分钟

移动端rem适配

`1rem 的大小就是1个 html 设置的 font-size 的大小

如果需要使用 rem 单位进行适配,推荐使用以下两个工具:

其他设计稿尺寸

如果设计稿的尺寸不是 375,而是 750 或其他大小,可以将 rootValue 配置调整为:

// postcss.config.js 
module.exports = {
  plugins: {
    // postcss-pxtorem 插件的版本需要 >= 5.0.0'postcss-pxtorem': {
      rootValue({ file }) {
        return file.indexOf('vant') !== -1 ? 37.5 : 75;
      },
      propList: ['*'],
    },
  },
};

一次性将目录下的所有文件引入

require.context(directory,useSubdirectories,regExp)

  • directory:表示检索的目录
  • useSubdirectories:表示是否检索子文件夹
  • regExp:匹配文件的正则表达式,一般是文件名 例如 require.context("@/views/components",false,/.vue$/)

最常见的六种跨域解决方案

前言:什么是跨域?

跨域就是当在页面上发送ajax请求时,由于浏览器同源策略的限制,要求当前页面和服务端必须同源,也就是协议、域名和端口号必须一致
在这里插入图片描述
如果协议、域名和端口号中有其中一个不一致,则浏览器视为跨域,进行拦截。

在这里插入图片描述

1、JSONP方式解决跨域:

jsonp的原理就是利用了script标签不受浏览器同源策略的限制,然后和后端一起配合来解决跨域问题的。

具体的实现就是在客户端创建一个script标签,然后把请求后端的接口拼接一个回调函数名称作为参数传给后端,并且赋值给script标签的src属性,然后把script标签添加到body中,当后端接收到客户端的请求时,会解析得到回调函数名称,然后把数据和回调函数名称拼接成函数调用的形式返回,客户端解析后会调用定义好的回调函数,然后在回调函数中就可以获取到后端返回的数据了。

页面中可能会存在多个jsonp,所以可以封装一个jsonp方法,客户端代码如下:

    // 封装一个jsonp函数
    function jsonp({url, params, callback}) {
        return new Promise((resolve, reject) => {
            // 定义回调函数
            window[callback] = function(data) {
                resolve(data)
            }
          
            const script = document.createElement('script') // 创建script标签
            params = {...params, callback}
            const arr = []
            for(const key in params) {
                if(params.hasOwnProperty(key)) { // 判断当前key是否是params对象自身的属性,有可能会是原型上的属性,所以需要判断一下
                    arr.push(`${key}=${params[key]}`)
                }
            }
            url += `?${arr.join('&')}` // 拼接参数
            script.async = true
            script.src = url
            document.body.appendChild(script)
            script.onload = () => {
                document.body.removeChild(script)
            }
        })
    }
	// 使用jsonp
    jsonp({
        url: 'http://127.0.0.1:8081/user',
        params:{id: '1'},
        callback: 'getUserData'
    }).then(res => {
        console.log('res:', res)
    })

服务端代码如下(nodeJS):

const http = require('http')
const url = require('url')

// 创建server
const server = http.createServer()
// 监听http请求
server.on('request', (req, res) => {
    // 获取客户端传来的回调函数名称
    const {callback} = url.parse(req.url, true).query
    const user = { // 模拟返回数据
        id: 1, 
        name: 'zhangsan',
        age: 12
    }
    // 把数据和回调函数名称拼接成函数调用的方式返回
    const result = `${callback}(${JSON.stringify(user)})`
    res.end(result)
})

// 设置监听端口
server.listen(8081, function() {
    console.log('server is running on 8081 port!')
})

jsonp的优点就是兼容性好,可以解决主流浏览器的跨域问题,缺点是仅支持GET请求,不安全,可能遭受xss攻击。

2、CORS方式解决跨域

3、搭建Node代理服务器解决跨域

4、Nginx反向代理解决跨域

5、postMessage方式解决跨域

6、Websocket方式解决跨域

总结:

  • jsonp的原理是利用了script标签不受浏览器同源策略的限制,img和link标签也是不受浏览器同源策略限制的。
  • 跨域是浏览器限制,服务端和服务端之间通信是不受浏览器同源策略限制的。
  • 所有跨域的解决方案都是需要服务端配合的。
  • 最常用的跨域解决方案是CORS、Node代理服务器和Nginx反向代理方式。
  • postMessage更多的是用在多个文档,窗口之间发送数据。
  • 原文链接:blog.csdn.net/m0_37873510…

登录

1、token简单登录

  • 前端收集登录数据(用户名、密码|手机号、验证码)
  • 后端返回token、refreshToken
  • 下次网络请求将token携带给后端
  • token过期主动处理:(和后端约定一个token过期的时间,在请求拦截器里做token是否过期的判断)
  • 如果token过期了则拿着refreshToken进行请求新的token(如果refreshToken过期了则跳到登录页重新登录)
  • token过期被动处理:根据状态码做异常逻辑处理-->例:401 token失效,需跳到登录页
  • token安全吗?比如token存在localstorage中,比如别人偷取了自己登录的token可以访问网站吗?不行的,因为请求会受到浏览器同源策略的限制

路由

1、静态路由

每个人都可以访问的(登录、404、首页)

constantRoute = []

2、动态路由

根据不同的用户具有不同的访问权限

const varRoute = [
  {
    path:'dashboard',
    component:Layout,
    children:[
      path:'',
      component:() => import('@/views/dashboard/index'),
      meta: { title: '首页', icon: 'dashboard', affix: true }
    ]
  }
]

树形结构的处理

const res = [
      { name: '技术部', id: 1, pid: '' },
      { name: '客户端', id: 2, pid: 1 },
      { name: '测试部', id: 3, pid: '' },
      { name: '代言', id: 4, pid: 3 },
      { name: '笠逍', id: 5, pid: 2 },
      { name: 'rocket', id: 6, pid: 5 },
      { name: '产品', id: 7, pid: '' }
    ]
    const fn = (arr, id) => {
      const deelFn = (id) => {
        let newArr = [];
        arr.forEach((val) => {
          if (val.pid === id) {
            let children = deelFn(val.id)
            if (children.length) val.children = children
            newArr.push(val)
          }
        })
        return newArr
      }
      return deelFn(id)
    }
    console.log(fn(res, ''));

excle导入导出

实现excel导入功能

npm install xlsx -S

2.在src/components/UploadExcel下创建UploadExcel.vue组件

本文是将vue-element-admin提供的组件复制到src/components/UploadExcel下,以下是vue-element-admin提供的组件代码:

<template>
  <div>
    <input ref="excel-upload-input" class="excel-upload-input" type="file" accept=".xlsx, .xls" @change="handleClick">
    <div class="drop" @drop="handleDrop" @dragover="handleDragover" @dragenter="handleDragover">
      Drop excel file here or
      <el-button :loading="loading" style="margin-left:16px;" size="mini" type="primary" @click="handleUpload">
        Browse
      </el-button>
    </div>
  </div>
</template>

<script>
import XLSX from 'xlsx'

export default {
  props: {
    beforeUpload: Function, // eslint-disable-line
    onSuccess: Function// eslint-disable-line
  },
  data() {
    return {
      loading: false,
      excelData: {
        header: null,
        results: null
      }
    }
  },
  methods: {
    generateData({ header, results }) {
      this.excelData.header = header
      this.excelData.results = results
      this.onSuccess && this.onSuccess(this.excelData)
    },
    handleDrop(e) {
      e.stopPropagation()
      e.preventDefault()
      if (this.loading) return
      const files = e.dataTransfer.files
      if (files.length !== 1) {
        this.$message.error('Only support uploading one file!')
        return
      }
      const rawFile = files[0] // only use files[0]

      if (!this.isExcel(rawFile)) {
        this.$message.error('Only supports upload .xlsx, .xls, .csv suffix files')
        return false
      }
      this.upload(rawFile)
      e.stopPropagation()
      e.preventDefault()
    },
    handleDragover(e) {
      e.stopPropagation()
      e.preventDefault()
      e.dataTransfer.dropEffect = 'copy'
    },
    handleUpload() {
      this.$refs['excel-upload-input'].click()
    },
    handleClick(e) {
      const files = e.target.files
      const rawFile = files[0] // only use files[0]
      if (!rawFile) return
      this.upload(rawFile)
    },
    upload(rawFile) {
      this.$refs['excel-upload-input'].value = null // fix can't select the same excel

      if (!this.beforeUpload) {
        this.readerData(rawFile)
        return
      }
      const before = this.beforeUpload(rawFile)
      if (before) {
        this.readerData(rawFile)
      }
    },
    readerData(rawFile) {
      this.loading = true
      return new Promise((resolve, reject) => {
        const reader = new FileReader()
        reader.onload = e => {
          const data = e.target.result
          const workbook = XLSX.read(data, { type: 'array' })
          const firstSheetName = workbook.SheetNames[0]
          const worksheet = workbook.Sheets[firstSheetName]
          const header = this.getHeaderRow(worksheet)
          const results = XLSX.utils.sheet_to_json(worksheet)
          this.generateData({ header, results })
          this.loading = false
          resolve()
        }
        reader.readAsArrayBuffer(rawFile)
      })
    },
    getHeaderRow(sheet) {
      const headers = []
      const range = XLSX.utils.decode_range(sheet['!ref'])
      let C
      const R = range.s.r
      /* start in the first row */
      for (C = range.s.c; C <= range.e.c; ++C) { /* walk every column in the range */
        const cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })]
        /* find the cell in the first row */
        let hdr = 'UNKNOWN ' + C // <-- replace with your desired default
        if (cell && cell.t) hdr = XLSX.utils.format_cell(cell)
        headers.push(hdr)
      }
      return headers
    },
    isExcel(file) {
      return /.(xlsx|xls|csv)$/.test(file.name)
    }
  }
}
</script>

<style scoped>
.excel-upload-input{
  display: none;
  z-index: -9999;
}
.drop{
  border: 2px dashed #bbb;
  width: 600px;
  height: 160px;
  line-height: 160px;
  margin: 0 auto;
  font-size: 24px;
  border-radius: 5px;
  text-align: center;
  color: #bbb;
  position: relative;
}
</style>

Excel文档:panjiachen.gitee.io/vue-element…