input正则校验
let regexp = '^1[3456789]\d{9}$'
<input pattern="regexp" required>
动态存在某个值
有些时候,后端返回的数据里动态存在某个值,也就意味着,有时候有这个数据,有时候没有,然后甩你一句话,“有就显示,没有就不显示”,作为前端的我们自然很严谨
// 模拟后端数据
let result = {
status:200,
codeMsg:'success',
data:{
userInfo:{
age:18,
hobby:['敲代码','打篮球']
}
}
}
// 前端严谨写法
if(result.data){
if(result.data.userInfo){
if(result.data.userInfo.hobby){
if(Array.isArray(result.data.userInfo.hobby)){
if(result.data.userInfo.hobby.length){
//遍历 result.data.userInfo.hobby 进行渲染显示
}
}
}
}
}
// 第一种用 `&&` 进行优化
if ( result.data && result.data.userInfo &&
result.data.userInfo.hobby &&
Array.isArray(result.data.userInfo.hobby) &&
result.data.userInfo.hobby.length )
{
//遍历 result.data.userInfo.hobby 进行渲染显示
}
// 第二种,`try catch `策略,严谨但又懒的前端
try {
if(result.data.userInfo.hobby.length){
//遍历 result.data.userInfo.hobby 进行渲染显示
}
} catch (error) { }
// 第三种可选项 (`?`)
if(result?.data?.userInfo?.hobby?.length){
//遍历 result.data.userInfo.hobby 进行渲染显示
}
封装一个获取位置的方法
function getPosition(direction){
return ({
left:"左",
right:"右",
top:"上",
bottom:"下"
})[direction] || "未知"
}
判空并赋值
// 例子
let first = 'abc';
if (first !== null || first !== undefined || first !== '') {}
// 优化
let second = first || '空值';
console.log(second, 'second');
给变量默认值
let toto
console.log(toto) //undefined
toto = toto ?? 'default value'
console.log(toto) //default value
条件简写
// 例子
if(condition){ toto() }
// 优化
condition && toto()
可选项 (?)
检查对象的某些属性是否存在,然后才能再处理它,不然会报错
const toto = { a: { b: { c: 5 } } }
console.log(toto?.a?.b?.c) // 5
console.log(toto?.a?.b?.d) // 5undefined
// 例子
if (!!toto.a && !!toto.a.b && !!toto.a.b.c) { ... } // toto.a.b.c exist;
// 优化
if (toto.a?.b?.c?.d) { ... }
双!操作符将任何变量转换为布尔值
const toto = null;
console.log(!!toto,'!!toto') // false
避免if过长
if (value === 'a' || value === 'b' || value === 'c') { ... }
// 优化
if (['a', 'b', 'c'].includes(value)) { ... }
移除type="number"尾部的箭头
<input type="number" class="no-arrow" />
/* 关键css */
.no-arrow::-webkit-inner-spin-button {
-webkit-appearance: none;
}
巧用not选择器
有些情况下
所有的元素都需要某些样式,唯独最后一个不需要,这时候使用not选择器将会特别方便
li:not(:last-child){ border-bottom: 1px solid #ebedf0; }
节流函数
//节流函数
throttle() {
//保持this的指向始终指向vue实例
var that = this;
if (!that.statu) {
return;
}
that.statu = false;
setTimeout(function() {
console.log(new Date());
that.search();
that.statu = true;
}, 3000);
},
v-if和v-for不建议同时使用
问题
- v-for的优先级比v-if高,每次v-for都会执行v-if,造成不必要的计算
<li v-for="(item,index) in list" v-if="item.isActive" :key="item.id">
{{ item.name }}
</li>
如上例子即使用100个item中只有一个需要展示 使用了v-if也是需要循环整个数组的、这在性能上是极大的浪费
解决
1、如何实在循环外部可以在外层嵌套已成template(页面不生成dom节点)、在外层v-if判断、然后在进行使用v-for循环
<template v-if="isShow">
<div v-for="(item,index) in list" v-if="item.isActive" :key="item.id">
{{ item.name }}
</div>
</template>
2、如果条件出现在循环内部、可以通过计算属性computed提前过滤掉那些不需要展示的数据
computed: {
listData: function() {
return this.list.filter(function (item) {
return item.isShow
})
}
}
v-for key作用
1.给每个节点做唯一标识 2.高效的更新虚拟DOM
冒泡排序
numbersSort1(arr = []) {
var len = arr.length;
for (var i = 0; i < len - 1; i++) {
for (var j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
// 相邻元素两两对比,元素交换的时候用第三者变量来暂存数据,最后用这个变量去替换原数据
var temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
return arr;
},
等待多个异步函数
async fun1() {
const res = await http(url1, query2)
}
async fun2() {
const res = await http(url2, query2)
}
async fun() {
await promise.all([fun1,fun2])
}
// Promise.all 实际上是一个函数,它接受一个 promises 数组并返回一个 Promise。
然后当所有的 promises 都完成时会得到 resolve 或者当其中一个被拒绝时会得到 rejected。
获取对象某个值
let obj = {a: '1',b: '2'}
console.log('获取对象值',(obj)['a']);
switch优化
// 1.对象优化
previewWeek(i){
return ({
1:'星期一',
2:'星期二',
3:'星期三',
4:'星期四',
5:'星期五',
6:'星期六',
7:'星期日',
})[i] || ''
}
// 2.数组优化
previewWeek(i) {
return i > 0 && i < 8 ? '星期' + ['一', '二', '三', '四', '五', '六', '日'][i - 1] : '';
}
// 3.map优化
function previewWeek(i){
let weeksMap = new Map([
[1, '一'],
[2, '二'],
[3, '三'],
[4, '四'],
[5, '五'],
[6, '六'],
[7, '日']
]);
return weeksMap.get(i)?'星期'+weeksMap.get(i):''
}
// 4.## includes 优化代码
function verifyIdentity(identityId){
if([1,2,3,4].includes(identityId)){
return '你的身份合法,请通行!'
}else{
return '你的身份未知,警告!'
}
}
// 最终优化实现:includes + 三元
function verifyIdentity(identityId){
return [1,2,3,4].includes(identityId)?'你的身份合法,请通行!':'你的身份未知,警告!'
}
清空数组方式
let arr = [1,2,3,4];
arr.length = 0;
获取用户设备
// 获取用户设备
function getUserMedia(constraints, success, error) {
if (navigator.mediaDevices.getUserMedia) {
//最新的标准API
navigator.mediaDevices
.getUserMedia(constraints)
.then(success)
.catch(error);
} else if (navigator.webkitGetUserMedia) {
//webkit核心浏览器
navigator.webkitGetUserMedia(constraints, success, error);
} else if (navigator.mozGetUserMedia) {
//firfox浏览器
navigator.mozGetUserMedia(constraints, success, error);
} else if (navigator.getUserMedia) {
//旧版API
navigator.getUserMedia(constraints, success, error);
}
}
watch监听
watch: {
// 第一种方式:监听整个对象,每个属性值的变化都会执行handler
// 注意:属性值发生变化后,handler执行后获取的 newVal 值和 oldVal 值是一样的
food: {
// 每个属性值发生变化就会调用这个函数
handler(newVal, oldVal) {
console.log('oldVal:', oldVal)
console.log('newVal:', newVal)
},
// 立即处理 进入页面就触发
immediate: true,
// 深度监听 属性的变化
deep: true
},
// 第二种方式:监听对象的某个属性,被监听的属性值发生变化就会执行函数
// 函数执行后,获取的 newVal 值和 oldVal 值不一样
'food.name'(newVal, oldVal) {
console.log('oldVal:', oldVal) // 冰激凌
console.log('newVal:', newVal) // 棒棒糖
}
}
截取字符串
// substring(beginIndex,endIndex) 方法返回字符串的子字符串。
// beginIndex -- 起始索引(包括), 索引从 0 开始。
// endIndex -- 结束索引(不包括)。
names = ',某某分包单位'
names = names.substring(1);
// 输出:某某设计单位
检索数组
// currDepartId.includes(item.key)
// currDepartId.includes(item.key)
for(let item of this.dataList){
// console.log(currDepartId.includes(item.key))
if(currDepartId.includes(item.key)){
names+=","+item.title
}
}
递归遍历
reWriterWithSlot(arr){
for(let item of arr){
if(item.children && item.children.length>0){
this.reWriterWithSlot(item.children)
let temp = Object.assign({},item)
temp.children = {}
this.dataList.push(temp)
}else{
this.dataList.push(item)
item.scopedSlots={ title: 'title' }
}
}
},
判断数组是否存在
item.children && item.children.length>0
文本溢出处理
//单行
.single {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
//多行
.more {
display: -webkit-box !important;
overflow: hidden;
text-overflow: ellipsis;
work-break: break-all;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2; //指定行数
}
判断系统
created(){
//判断系统
let u = navigator.userAgent;
let isAndroid = u.indexOf('Android') > -1 || u.indexOf('Linux') > -1; //g
let isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
if (isAndroid) {
this.system = 'Android';
} else if (isIOS) {
this.system = 'IOS';
} else {
this.system = 'pc';
}
},
获取初始化数据
方法一
//初始化时获取基本数据
async initData(){
if (!this.latitude) {
//获取位置信息
let res = await msiteAddress(this.geohash);
// 记录当前经度纬度进入vuex
this.RECORD_ADDRESS(res);
}
//获取商铺信息
this.shopDetailData = await shopDetails(this.shopId, this.latitude, this.longitude);
//隐藏加载动画
this.hideLoading();
},
方法二
async initData(){
try{
this.city = await cityGuess();
const countData = await getResturantsCount();
if (countData.status == 1) {
this.count = countData.count;
}else{
throw new Error('获取数据失败');
}
this.getResturants();
}catch(err){
console.log('获取数据失败', err);
}
},
vuex提交
methods: {
...mapMutations([
'RECORD_ADDRESS','ADD_CART','REDUCE_CART','INIT_BUYCART','CLEAR_CART','RECORD_SHOPDETAIL'
]),
//初始化时获取基本数据
async initData(){
if (!this.latitude) {
//获取位置信息
let res = await msiteAddress(this.geohash);
// 记录当前经度纬度进入vuex
this.RECORD_ADDRESS(res);
}
},
}
计算属性
//购物车中总共商品的数量
totalNum: function (){
let num = 0;
this.cartFoodList.forEach(item => {
num += item.num
})
return num
},
更新数据
async updateShop(){
this.dialogFormVisible = false;
try{
Object.assign(this.selectTable, this.address);
this.selectTable.category = this.selectedCategory.join('/');
const res = await updateResturant(this.selectTable)
if (res.status == 1) {
this.$message({
type: 'success',
message: '更新店铺信息成功'
});
this.getResturants();
}else{
this.$message({
type: 'error',
message: res.message
});
}
}catch(err){
console.log('更新餐馆信息失败', err);
}
},
自定义参数
const params = {
...this.foodForm,
category_id: this.selectValue.id,
restaurant_id: this.restaurant_id,
}
使用less的mixin方法
@import '../style/mixin';
span{
.sc(14px, #999);
transition: all 400ms;
}
去除滚动条
/* 去掉滚动条 */
&::-webkit-scrollbar {
display: none;
}
获取初始数据
loadData() {
this.dataSource = []
getPermissionList().then((res) => {
if (res.success) {
console.log(res.result)
this.dataSource = res.result
}
})
},
接口赋值
let { result } = data;
let list = [];
if (result) {
if (Array.isArray(result)) {
list = result
} else if (Array.isArray(result.records)) {
list = result.records
}
}
变量方法
@click="handleAdd(1)"
handleAdd(num) {
if (num == 1) {
this.$refs.departModal.add()
this.$refs.departModal.title = '新增'
} else {
this.$refs.departModal.add(this.rightClickSelectedKey)
this.$refs.departModal.title = '新增'
}
},
获取路由参数
created() {
this.currFlowId = this.$route.params.id
this.currFlowName = this.$route.params.name
// this.loadTree()
},
导入样式
<style scoped>
@import '~@assets/less/common.less';
</style>
删除方法
handleDelete() {
var that = this
this.$confirm({
title: '确认删除',
content: '确定要删除此部门以及子节点数据吗?',
onOk: function () {
deleteByDepartId({id: that.rightClickSelectedKey}).then((resp) => {
if (resp.success) {
//删除成功后,去除已选中中的数据
that.checkedKeys.splice(that.checkedKeys.findIndex(key => key === that.rightClickSelectedKey), 1);
that.$message.success('删除成功!')
that.loadTree()
//删除后同步清空右侧基本信息内容
let orgCode=that.model.orgCode;
if(orgCode && orgCode === that.rightClickSelectedOrgCode){
that.onClearSelected()
}
} else {
that.$message.warning('删除失败!')
}
})
}
})
},