移动端rem适配
`1rem 的大小就是1个 html 设置的 font-size 的大小
如果需要使用 rem 单位进行适配,推荐使用以下两个工具:
- postcss-pxtorem 是一款 PostCSS 插件,用于将 px 单位转化为 rem 单位
- lib-flexible 用于设置 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…