Vue 项目里的常用写法和坑点。基础语法和原理看 Vue学习笔记。
基础
常用:const/let、对象字面量增强、filter/map、Promise。
1 2 3 4 5 6 7 8 9 10 11 12 13
| const list = [1, 2, 3] const result = list.filter(item => item > 1).map(item => item * 2)
new Promise((resolve, reject) => { const ok = true if (ok) { resolve(result) } else { reject(new Error('request error')) } }).then(res => { console.log(res) })
|
重点:
1、优先 const,变量会变再用 let
2、箭头函数注意 this
3、列表处理优先 filter/map
4、异步请求先把 Promise 链写顺
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const name = 'lemon' const age = 18
const user = { name, age, print() { console.log(`${name}-${age}`) } }
const nums = [1, 2, 4, 5, 6, 9, 10, 15] const evenNums = nums.filter(item => item % 2 === 0) const doubled = nums.map(item => item * 2)
|
有周趋势、补零这类场景时,Array.from(new Array(7)) 也很常用。
1 2 3 4 5 6 7 8 9 10 11 12 13
| function getWeekDays() { const now = new Date() const day = now.getDay() || 7 return Array.from({ length: 7 }, (_, index) => { const current = new Date(now) current.setDate(now.getDate() - day + index + 1) return current }) }
function fillZero(value) { return value < 10 ? `0${value}` : `${value}` }
|
工具函数
列表、搜索、导出、联调时经常要补几段基础工具。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| function formatDate(date) { const target = new Date(date) const year = target.getFullYear() const month = `${target.getMonth() + 1}`.padStart(2, '0') const day = `${target.getDate()}`.padStart(2, '0') const hour = `${target.getHours()}`.padStart(2, '0') const minute = `${target.getMinutes()}`.padStart(2, '0') const second = `${target.getSeconds()}`.padStart(2, '0') return `${year}-${month}-${day} ${hour}:${minute}:${second}` }
function debounce(fn, delay = 300) { let timer = null return function (...args) { clearTimeout(timer) timer = setTimeout(() => fn.apply(this, args), delay) } }
function throttle(fn, delay = 300) { let lastTime = 0 return function (...args) { const now = Date.now() if (now - lastTime < delay) { return } lastTime = now fn.apply(this, args) } }
|
组件
常见点:
1、父传子、子传父
2、props 校验
3、data 写成函数的原因
4、$refs、插槽、事件派发怎么配合
5、数组和对象更新后页面不刷新的处理
1 2 3 4 5 6
| props: { number1: { type: Number, default: 0 } }
|
请求
请求层主要看实例配置、拦截器、参数位置、请求头。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const instance = axios.create({ baseURL: '/api', timeout: 5000 })
instance.interceptors.request.use(config => { return config })
axios.post('/api/user', data, { headers: { 'Content-Type': 'application/json' } })
|
登录态一般配合 sessionStorage 和请求拦截器一起用:
1 2 3 4 5 6 7 8 9
| window.sessionStorage.setItem('token', res.data.token)
instance.interceptors.request.use(config => { const token = window.sessionStorage.getItem('token') if (token) { config.headers.Authorization = token } return config })
|
常见问题:
1、get/post/put/delete 传参位置不对
2、content-type 和后端约定不一致
3、模块加载超时或者代理没配好
4、浏览器缓存和旧数据影响结果
登录态
高频操作:
1、登录成功后写 token
2、退出时清理本地登录态
3、页面初始化后按 token 拉菜单或用户信息
1 2 3 4
| logout() { window.sessionStorage.clear() this.$router.push('/login') }
|
这类逻辑容易漏清理,结果就是退出后页面状态还在,但接口已经 401。
布局和存储
联调时除了接口,最常碰到的就是 flex 布局和浏览器存储。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| .box { display: flex; justify-content: center; align-items: center; }
.between { display: flex; justify-content: space-between; align-items: center; }
.item { flex: 1 1 200px; }
|
1 2 3 4 5 6
| document.querySelector('#preview').src = imageUrl document.querySelector('#panel').classList.add('is-open')
window.sessionStorage.setItem('token', token) const token = window.sessionStorage.getItem('token') document.cookie = `token=${token};path=/;max-age=${7 * 24 * 60 * 60}`
|
常见问题:
1、父元素没高度,align-items 看起来不生效
2、回显值存进了 sessionStorage,但退出或切页没有清理
3、字段回来了,DOM 也拿到了,但样式层把结果盖掉了
工程化
依赖和脚手架问题先查环境,再查代码。
常见问题:
1、vue-cli-service 找不到
2、npm install 失败
3、loader 版本对不上
4、脚手架能起,但是页面空白或者编译报错
1 2
| rm -rf node_modules npm install
|
重点排查 Node 版本、锁文件、node_modules、构建日志。
开发环境接口不通时,代理配置也要第一时间看:
1 2 3 4 5 6 7 8 9 10 11 12 13
| module.exports = { devServer: { proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true, pathRewrite: { '^/api': '' } } } } }
|
插件类问题不要一上来怀疑业务代码,先确认初始化时机:
1 2 3 4 5
| mounted() { this.$nextTick(() => { }) }
|
Element UI
高频场景:
1、表单回显不完整
2、树形控件刷新后状态丢失
3、表格和分页联动不对
4、图表配置项改了但页面不生效
5、组件状态和业务状态没有对齐
表单
表单重点是 rules、prop、ref 对齐,重置用 resetFields()。
组件库接入先把安装和全局注册做对:
1 2 3 4
| import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| reset() { this.$refs.loginFormRef.resetFields() }
data() { const valiCateDeleted = (rule, value, cb) => { if (value === 0 || value === '1' || value === '0') { return cb() } cb(new Error('请选择状态')) }
return { loginFormRules: { mobile: [{ required: true, message: '请输入手机号', trigger: 'blur' }], deleted: [{ validator: valiCateDeleted, trigger: 'change' }] } } }
|
表格和弹框
常一起出现:el-table、el-dialog、MessageBox、树形表格。
1 2 3 4
| <el-table :data="tableData" border stripe> <el-table-column prop="username" label="用户名"></el-table-column> <el-table-column prop="mobile" label="手机号"></el-table-column> </el-table>
|
1 2 3 4 5
| this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' })
|
常见问题:
1、删除确认后没做列表刷新
2、弹框关闭后表单状态没清干净
3、表格分页切换后查询条件丢失
4、树形表格数据结构和列配置没对齐
如果是菜单页或后台壳子页,el-menu 也很常见:
1 2 3 4 5 6
| <el-menu :default-active="activePath" router unique-opened> <el-submenu index="1"> <template slot="title">用户管理</template> <el-menu-item index="/users">用户列表</el-menu-item> </el-submenu> </el-menu>
|
级联和远程搜索
商品分类、组织树、项目列表常用这两类组件。
1 2 3 4 5 6
| <el-cascader v-model="selectedCatKeys" :options="cascaderList" :props="cateProps" @change="handleChange"> </el-cascader>
|
1 2 3 4 5
| cateProps: { label: 'catName', value: 'id', children: 'children' }
|
1 2 3 4 5 6
| <el-select v-model="curProject" filterable remote :remote-method="remoteMethod"> </el-select>
|
关键点:后端返回结构、回显值、联动刷新一致。
树形表格一般还会配插件:
1 2 3
| import TreeTable from 'vue-table-with-tree-grid'
Vue.component('tree-table', TreeTable)
|
Ant Design Vue
如果项目不是 Element UI,而是 Ant Design Vue,分页和表格配置也经常要改:
1 2 3 4 5 6
| <a-table :columns="columns" :data-source="dataSource" :pagination="pagination" rowKey="id"> </a-table>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| data() { return { pagination: { current: 1, pageSize: 10, total: 0, showTotal: total => `共 ${total} 条` } } }
handleTableChange(pagination) { this.pagination.current = pagination.current this.pagination.pageSize = pagination.pageSize this.loadData() }
|
常见坑
最常见:
1、resetFields() 调了但 prop 没配对,结果看起来没重置
2、树控件刷新了数据,但选中状态和展开状态丢了
3、Dialog 关闭后局部状态没清理,二次打开还是旧数据
4、远程搜索请求回来了,但 label/value 映射错了,导致选不上
5、表格行操作、分页、筛选三者互相打架
排查顺序
固定顺序:
1、环境和依赖
2、请求头、参数和接口返回
3、浏览器控制台和 network
4、组件状态和页面样式