1)一列图标的大小调整和对齐
这种情况经常发生在UI所给图标大小不一,需要手动调整的情况。
1)宽高使用作用是限定图标在一个box里面;
2)position和transform的使用是使图标随着中间点放大缩小;
3)left和top这些方位属性用于调整图标竖排或横排的对齐位置。
width: 22px;
height: 22px;
position: absolute;
top: 27px;
left: 25px;
transform: translate(-50%, -50%);
说明:经过上面这些属性设置,大小不一的图标就可以通过手动的方式进行调整,而且调整的基准点是中间点,非常方便。
2)关于多个条件的逻辑判断
有些时候需要判断的条件过多,这时候不应该混合这些条件一起做判断,应该分开每个独立的条件,然后分别结合做判断,这样编写代码逻辑会更清晰。
hasTab() {
return this.agentTeamLevel > 1 && this.agentTeamLevel > this.agentLevel;
},
isWx() {
return this.$store.state.isWx;
}
说明:上面是两个计算属性,用于判断什么时候有tab栏和是不是微信端。这两个计算属性结合着使用可以产生四种情况,即微信端有和没有tab的情况、非微信端有和没有tab的情况。然后开发中会根据每种情况给不同的页面样式,比如页面的头部样式的变化等等。
如果此时将两个计算属性内部的判断混合着使用,而不是像上面这样根据判断类别划分独立的判断条件,会很容易造成混淆。
3)关于路由传参
使用vue开发项目一般不建议使用路由进行参数的传递,因为很多时候会发生从多个地方跳到某个页面的情况,这时候就无法确定上一个页面是否就是传参过来的页面了,会发生页面跳转时没有路由参数传递的情况。
this.$router.push({ name: "memberOrder", query: { status: str } });
所以建议使用的是路由导航守卫。跳转到某一个页面前做判断处理即可。
beforeRouteEnter(to, from, next) {
// 根据to或者from里的参数属性进行判断
if (from......) {
next("/agent/agent-closed");
} else {
next();
}
// 或者直接发送请求拿到数据进行判断
axios.get("/shop/member/center/index").then(res => {
if (res.code == 200 && res.data.agent_config_level == 0) {
next("/agent/agent-closed");
} else {
next();
}
}
4)Form表单提交前的验证
这里说明的是iView框架的Form表单提交验证。主要分为三个部分:表单数据,验证规则和验证方法。
<Form ref="formValidate" :model="formValidate" :rules="ruleValidate" :label-width="80">
<FormItem label="Name" prop="name">
<Input v-model="formValidate.name" placeholder="Enter your name"></Input>
</FormItem>
<FormItem label="Gender" prop="gender">
<RadioGroup v-model="formValidate.gender">
<Radio label="male">Male</Radio>
<Radio label="female">Female</Radio>
</RadioGroup>
</FormItem>
<FormItem label="Hobby" prop="interest">
<CheckboxGroup v-model="formValidate.interest">
<Checkbox label="Eat"></Checkbox>
<Checkbox label="Sleep"></Checkbox>
<Checkbox label="Run"></Checkbox>
<Checkbox label="Movie"></Checkbox>
</CheckboxGroup>
</FormItem>
<FormItem>
<Button type="primary" @click="handleSubmit('formValidate')">Submit</Button>
<Button @click="handleReset('formValidate')">Reset</Button>
</FormItem>
</Form>
说明:通过v-model绑定表单数据,每一个表单项目FormItem记得加上prop属性,且名称要和表单数据formValidate里定义的名称一致。
export default {
data () {
return {
formValidate: {
name: '',
gender: '',
interest: []
},
ruleValidate: {
name: [
{ required: true, message: 'The name cannot be empty', trigger: 'blur' }
],
gender: [
{ required: true, message: 'Please select gender', trigger: 'change' }
],
interest: [
{ required: true, type: 'array', min: 1, message: 'Choose at least one hobby', trigger: 'change' },
{ type: 'array', max: 2, message: 'Choose two hobbies at best', trigger: 'change' }
]
}
}
},
说明:通过在data()里定义表单数据和验证规则。
验证规则ruleValidate说明
required: true,指的是该项为必填项;
trigger: 'blur',指的是触发条件是失去焦点;
trigger: 'change',指的是触发条件是值改变;
message: '...',验证不通过时的提示内容;
其他规则可由名字知道大概的验证规则,比如max、type这些见名知意的规则。
export default {
methods: {
handleSubmit (name) {
this.$refs[name].validate((valid) => {
if (valid) {
this.$Message.success('Success!');
} else {
this.$Message.error('Fail!');
}
})
},
handleReset (name) {
this.$refs[name].resetFields();
}
}
}
说明:在methods里定义提交和重置方法,提交方法体里调用验证方法,验证数据,验证规则由ruleValidate给出。
自定义验证
当然我们还可以进行自定义的验证方式,通过在data()里定义验证方法来实现:
<Form ref="formCustom" :model="formCustom" :rules="ruleCustom" :label-width="80">
<FormItem label="Password" prop="passwd">
<Input type="password" v-model="formCustom.passwd"></Input>
</FormItem>
<FormItem label="Confirm" prop="passwdCheck">
<Input type="password" v-model="formCustom.passwdCheck"></Input>
</FormItem>
</Form>
data () {
const validatePass = (rule, value, callback) => {
if (value === '') {
callback(new Error('Please enter your password'));
} else {
if (this.formCustom.passwdCheck !== '') {
// 对第二个密码框单独验证
this.$refs.formCustom.validateField('passwdCheck');
}
callback();
}
};
return {
formCustom: {
passwd: '',
passwdCheck: ''
},
ruleCustom: {
passwd: [
{ validator: validatePass, trigger: 'blur' }
]
}
}
},
说明:通过自定义方法的方式,就可以验证其他想要验证的项目。
5)Vue中的$set使用
在开发过程中,我们时常会遇到这样一种情况:向vue的data里边已经声明或者已经赋值的对象、数组(数组里边的值是对象)添加新的属性时,如果更新此属性的值,是不会更新视图的。
根据官方文档定义:如果在实例创建之后添加新的属性到实例上,它不会触发视图更新。
这是因为受现代 JavaScript 的限制 (以及废弃 Object.observe),Vue 不能检测到对象属性的添加或删除。
由于 Vue 会在初始化实例时对属性执行 getter/setter 转化过程,所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的。
为了使属性更新的同时视图也进行更新,可以使用$set方法:
this.$set(this.formValidate, "alipay_qrcode", "");
说明:语法说明,第一个参数指target,第二个指key,第三个是value。target类型规定为数组或对象,key类型为字符串或数字类型,而value值类型为any。
6)三目运算使用
很多简单的逻辑可以使用三目运算进行代替,使代码看起来更加简洁。
this.showModal ? this.showModal : "";
7)组件内守卫
很多时候通过路由进入某个组件之前需要进行状态判断,比如当前用户是否有权限访问该组件、组件功能是否打开等等这些状态需要判断。所以我们可以用到组件内守卫,在进到组件之前,即组件实例未被创建之前,做一些判断和操作。
组件内守卫有三个:
beforeRouteEnter
beforeRouteUpdate (2.2 新增)
beforeRouteLeave
这里进行beforeRouteEnter的说明。
beforeRouteEnter(to, from, next) {
axios.get("/shop/member/cloudstock/member/info").then(res => {
if (res.code == 502) {
next("/cloudstock/cloud-has-not-apply");
} else if (res.code == 501) {
next("/cloudstock/cloud-closed");
} else {
next(vm => {
vm.getAgentorInfo(res, from);
});
}
});
}
说明:在进入组件之前做了一些判断和操作,即先发送请求获取应用程序的状态信息,根据状态信息跳转到相应的页面。当然,我们还可以在next方法里传入回调函数,在实例创建后调用相应的方法,这里的vm指的是守卫执行后被创建的组件实例对象。
methods: {
/**
* 获取信息
*/
getAgentorInfo(res, from) {
//……
}
}
注意:next方法里不能使用this,因为这个守卫执行前,组件实例是还没有被创建的。守卫执行后,实例才被创建。
8)vant框架(组件库)的van-uploader使用
uploader用于文件上传,在很多时候我们前台需要将图片上传给后台服务器。上传文件时可以使用该组件,目测该组件是基于input标签进行封装的。
基本用法
使用该组件一般会给组件绑定回调函数,获取得到file对象,然后对file进行处理,将文件上传给后台服务器。
<van-uploader :after-read="afterRead" />
export default {
methods: {
afterRead(file) {
// 此时可以自行将文件上传至服务器
console.log(file);
}
}
};
用法进阶
有时候需要一次性上传多张图片,而且上传的图片还需提供删除功能,这时可以和其他组件、标签一起进行封装。
<template>
<div class="agent-cash" :class="{'not-padding-bottom':payTypeList.length<=0}">
<!-- 上传多张图片 -->
<div class="purchase-order-pay-msg" v-if="payTypeList.length">
<div class="purchase-order-pay-msg-text">请上传图片:</div>
<div class="purchase-order-pay-msg-phone">
<div
v-for="(item,index) in initial_pay_certificate"
:key="index"
class="purchase-order-pay-msg-image"
>
<img :src="item.content" alt @click="onViewImageClick(item.content)" />
<i class="iconfont icon-shanchu" style="background:#fff;border-radius:50%;" @click="initial_pay_certificate.splice(index, 1)"></i>
</div>
<van-uploader
multiple
:max-count="3"
:after-read="afterRead"
v-show="initial_pay_certificate.length < 3"
>
<div class="purchase-order-pay-msg-camera">
<i class="iconfont icon-camera"></i>
</div>
</van-uploader>
<span class="purchase-order-pay-msg-tip">最多上传3张</span>
</div>
</div>
<!-- 弹出组件,用于查看大图 -->
<van-popup v-model="imageShowStatus">
<div>
<img style="max-width: 290px;" :src="selectImageShow" alt />
</div>
</van-popup>
</div>
</template>
<script>
import { Uploader,Popup } from "vant";
export default {
name: "uploaderTest",
components: {
vanUploader: Uploader,
vanPopup: Popup
},
data() {
return {
initial_pay_certificate: [], //向后台发送的图片
selectImageShow: "", // 大图的src地址
imageShowStatus: false, // 查看大图
};
},
methods: {
/**
* 查看大图片
*/
onViewImageClick(val) {
this.selectImageShow = val;
this.imageShowStatus = true;
},
/**
* 图片上传之后的回调
*/
afterRead(file) {
if (file.constructor === Array) {
this.initial_pay_certificate.push(
...file.slice(0, 3 - this.initial_pay_certificate.length)
);
} else {
this.initial_pay_certificate.push(file);
}
}
}
</script>
说明:上面代码进行了上传图片的组件封装,该组件不仅可以上传多张图片(这里限制是3张,通过给uploader组件添加max-count属性进行限制),还拥有删除和查看大图的功能。其中查看大图功能通过popup组件实现,会有一个弹出图片和显示的效果
9)JSON数据的解析
JSON格式通常用于前端与服务器进行数据的交换,而JSON实例对象有两个常用的方法,这里进行说明:
JSON.parse():使用 JSON.parse() 方法将数据转换为 JavaScript 对象;
JSON.stringify():使用 JSON.stringify() 方法将 JavaScript 对象转换为字符串。
JSON.parse()
JSON.parse()方法有两个参数:
text:必需;
reviver:可选。
第一个参数是有效的JSON字符串,必填;第二个参数是一个转换结果的函数,使用JSON.parse()转换后的对象的每个成员调用该函数,可选。
举例,假如我们从服务器接收了以下text:
var text = '{ "name":"Runoob", "initDate":"2013-12-14", "site":"www.runoob.com"}';
var obj = JSON.parse(text, function (key, value) {
if (key == "initDate") {
return new Date(value);
} else {
return value;
}});
说明:我们使用 JSON.parse() 方法处理以上数据,将其转换为 JavaScript 对象。
这里还调用了转换结果函数,对象的每个成员调用该函数。key指对象成员的key值,value指对象成员的值,即键值对,比如 initDate:"2013-12-14"就是对象的一个成员,initDate指key,"2013-12-14"指value。因为JSON 不能存储 Date 对象,如果你需要存储 Date 对象,需要将其转换为字符串,之后再将字符串转换为 Date 对象。上面的转换结果函数目的就是将字符串转换为Date对象。
JSON.stringify()
JSON.stringify()有三个参数:
value:必需,要转换的 JavaScript 值(通常为对象或数组);
replacer:可选,用于转换结果的函数或数组;
space:可选,文本添加缩进、空格和换行符。
举例一,对象转为JSON字符串:
var obj = { "name":"runoob", "alexa":10000, "site":"www.runoob.com"};
var myJSON = JSON.stringify(obj);
举例二,数组转JSON字符串:
var arr = [ "Google", "Runoob", "Taobao", "Facebook" ];
var myJSON = JSON.stringify(arr);
10)Object对象使用
Object对象是JavaScript的标准内置对象之一,在这些标准内置对象的分类中,Object属于基本对象分类。
Object.keys()
它把一个对象的属性转换为数组。
该方法有一个参数,Object.keys(obj),该参数是指要进行枚举自身属性的对象,可以是普通对象,也可以是数组或字符串。假如传入该方法的参数是一个对象,那么调用该方法之后,会得到一个字符串数组,该数组的每个元素对应传入对象的每个key。
举例:
let person = {name:"jimson",age:26,address:"深圳",getName:function(){}};
Object.keys(person); // ["name", "age", "address","getName"] 属性数组
说明:数组中的属性名(key)的排列顺序和使用for...in循环遍历对象时返回的属性顺序一致。
而假如传入的参数是一个数组或字符串,虽然返回值也是一个字符串数组,但是数组的每个元素是传入参数的索引值。
举例:
let arr = [1,2,3,4,5,6];
Object.keys(arr); // ["0", "1", "2", "3", "4", "5"] 索引数组
举例二:
let str = "jimson字符串";
Object.keys(str); // ["0", "1", "2", "3", "4", "5", "6", "7", "8"] 索引数组
我们经常会使用它做一些其他处理:
let person = {name:"jimson",age:26,address:"深圳",getName:function(){}};
Object.keys(person).filter((key)=>{
person[key] // 获取到属性对应的值,然后做一些处理
});
Object.values()
它把一个对象的值转换为数组。Object.values()方法返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用for...in循环的顺序相同 ( 区别在于 for-in 循环枚举原型链中的属性 )。
举例:
var obj = { foo: 'bar', baz: 42 };
console.log(Object.values(obj)); // ['bar', 42] 值数组
// array like object
var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.values(obj)); // ['a', 'b', 'c'] 值数组
// array like object with random key ordering
// when we use numeric keys, the value returned in a numerical order according to the keys
var an_obj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.values(an_obj)); // ['b', 'c', 'a'] 值数组
说明:这里得到的都是值数组,而不同于Object.keys()的属性数组或索引数组。
Object.assign()
该方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
举例:
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
console.log(target); // Object { a: 1, b: 4, c: 5 }
console.log(returnedTarget); // Object { a: 1, b: 4, c: 5 }
说明:这里输出结果相同,因为调用方法之后返回的是目标对象,所以两个值相同。
注意:如果目标对象中的属性具有相同的键,则属性将被源对象中的属性覆盖。后面的源对象的属性将类似地覆盖前面的源对象的属性。这里目标对象和源具有相同的键b,源对象的属性覆盖目标对象的属性。所以如果不希望属性被覆盖,则慎重考虑使用该方法。