Vue开发中遇到问题记录
本篇是记录Vue真实开发中遇到的一些问题的记录,本人并非前端开发工程师,在Vue开发中也是摸爬滚打,博客为了不遗忘和加深记忆,所以本篇博客会随时更新。
注意:以下代码经过封装并且精简过的伪代码,不能够直接使用,仅提供思路
实现弹窗问题记录
场景:两个按钮点击之后出现的两个弹窗属于同一组件,通过dialogType来判断弹窗类型,然后通过传递不同的参数来控制隐藏、必填等操作。
需求:整个功能由三个组件构成:list、card、dialog,其中list是card列表,card展示内容,dialog是自定义弹窗。card上面存在两个按钮,分别是"退订",“退款”,要求是点击退订按钮时弹窗,弹窗内容为退订原因选择列表和退订说明输入框,同时退订原因必选;点击退款按钮时弹窗,弹窗内容为退订说明,退订说明要根据已存在的退订原因来判断是否必填(退订原因不展示)。
实现思路:退订按钮和退款按钮因为在同一个card中,所以需要的数据和内容基本上都是一样的,所以退订弹窗和退款弹窗共用一个自定义弹窗组件
弹窗实现: 弹窗实现以下几个步骤:
1、弹窗组件创建
通过需求进行组件内容组合,退订说明二者都需要,所以必须保留,其次退订原因是退订弹窗需要的,也必须保留,代码如下:
<template>
<div class="compose">
<div class="yd-confirm-hd label" >
<strong class="inputWriteMust tips">请选择退订原因</strong>
<!-- <p class="tipsText">请选择退订原因:</p> -->
</div>
<yd-radio-group
class="confirmbds"
v-model="checkId"
>
<div v-for="(item, index) in radioList" :key="index">
<div class="flex">
<yd-radio class="radios" :val="item.ID"></yd-radio>
<div>
{{ item.ID}}
</div>
</div>
</div>
</yd-radio-group>
<div class="confirmbds">
<input-cell
label="退订说明"
v-model="textContent"
type="textarea"
rows="5"
cols="3"
/>
</div>
<div class="confirmSelect">
<button @click="cancel()" class="cancel">取 消</button>
<button @click="define(checkId)" class="define">确 定</button>
</div>
</div>
</template>
2、弹窗展示
弹窗展示使用popup公共组件,该组件通过v-model:visible=“” 来控制隐藏/显示,在代码中通过对isPopupDisplay的改变就能够来控制弹窗展示了。
在下述代码中,使用card通过this.$emit(“showPopup”, data)向list传递dialog需要的数据,此时我们可以通过在传递的数据中添加dialogType属性让dialog来判断弹窗类型是退订还是退款。
同时通过this.$refs.dialog.getReasonsList()调用dialog中的获取退订原因的请求。
3、数据传递
完成数据传递,弹窗功能就算完成了,但是在控制必选的过程中出现了问题。因为mounted使用props属性不起作用,原因通过百度说是props可能会通过请求获取数据再传递给子组件,而mounted使用时props可能还没有完成请求而导致mounted使用的数据是默认数据(null)。
针对这个问题我试验过多个方案,但是都没有完美解决,比如通过监视props数据,发现props有值时给mustWriteTag(必填校验字段)和textContent(退订说明)的赋值,但会出现只触发一次的情况(props传值是在list触发的,需要刷新list页面才会再次传值,这显然不符合需求)。
最终我通过$refs传递数据,发现完美解决了该问题。通过this.$refs.dialog定位到子组件,然后可以获取到对应属性,这样就能够完成mustWriteTag和textContent的条件赋值了。
总结:
可以使用很多方式进行传值,常见的this.$emit(),prosp、this.$refs.xxx.xxx。
1、之所以不能够使用props传递数据原因:必填校验的控制以及退订说明的赋值不是简单的v-if和v-model就能实现的(如果能使用v-if和v-model实现就可以直接通过props传递数据就行了),而是条件赋值
2、可以通过this.$refs.ref调用对应子组件的方法和属性,完成属性赋值和方法调用
list.vue
<card
type="check"
@showPopup="isShowPopup"
/>
<yd-popup v-model="isPopupDisplay" position="center" width="80%">
<Dialog ref="dialog"
@backHandles="isPopupDisplay = false" />
</yd-popup>
<script>
method:{
isShowPopup(data){
if(data.dialogType == '1'){
this.$refs.dialog.getReasonsList();
}
setTimeout(() =>{
this.isPopupDisplay = true;
}, 200)
// 将card回传过来的客户信息赋值并传给弹窗
this.currentDialogInfo = data;
if (this.currentDialogInfo.dialogType == '0' && this.currentDialogInfo.paramCategory == '10041001'){
this.$refs.dialog.mustWriteTag = this.currentDialogInfo.paramCategory;
}
// 当弹窗类型为同意退款,并且存在退订说明时,textContent修改为当前退订说明
if(this.currentDialogInfo.dialogType == '0' && this.currentDialogInfo.unsubscriptionExplain != ''){
this.$refs.dialog.textContent = this.currentDialogInfo.unsubscriptionExplain;
}
},
updateDataList() {
this.resetData(xxx) //重置页数数据
this.getData()
},
</script>
card.vue
<template>
<div class="buttonList flex" >
<hz-button
name="退款"
@handleClick="setRefundConfirm(data)"
/>
<div>
<hz-button
name="退订"
@handleClick="setCancel(data)"
/>
</template>
<script>
method:{
setRefundConfirm(data) {
if (!data.soNo) {
this.showDialog(this.soNoError);
return;
}
data.dialogType = '0';
this.$emit("showPopup", data);
},
setCancel(data) {
if (!data.soNo) {
this.showDialog(this.soNoError);
return;
}
data.dialogType = '1';
this.$emit("showPopup", data);
</script>
dialog.vue
<template>
<div class="compose">
<div class="yd-confirm-hd label" >
<strong class="inputWriteMust tips">请选择退订原因</strong>
<!-- <p class="tipsText">请选择退订原因:</p> -->
</div>
<yd-radio-group
class="confirmbds"
v-model="checkId"
>
<div v-for="(item, index) in radioList" :key="index">
<div class="flex">
<yd-radio class="radios" :val="item.ID"></yd-radio>
<div>
{{ item.ID}}
</div>
</div>
</div>
</yd-radio-group>
<div class="confirmbds">
<input-cell
label="退订说明"
v-model="textContent"
type="textarea"
rows="5"
cols="3"
:inputWriteMust="this.mustWriteTag == 10041001"
/>
<!-- inputWriteMust是必填字段校验 -->
</div>
<div class="confirmSelect">
<button @click="cancel()" class="cancel">取 消</button>
<button @click="define(checkId)" class="define">确 定</button>
</div>
</div>
</template>
<script>
data() {
return {
checkId:"",
mustWriteTag: "",
radioList:[],
textContent:'',
};
},
props:{
tipsText:{
type:String
},
currentDialogInfo: {
type: Object,
default:()=>{ }
},
isShowExplain:{
type: Boolean
}
},
method:{
// 获取退订原因
getReasonsList(){
let vm = this;
this.$api.list.getReasonsList().then((result) => {
vm.radioList = result.dataInfo;
}).catch((err) => {
console.log(err);
});
},
}
</script>
4、关闭弹窗
通过this.$emit(‘backHandles’)将弹窗隐藏/显示字段置为false,弹窗就关闭了,发送请求,根据请求成功/失败来进行不同的操作。
值得注意的是要将data中使用的控制字段、输入字段置空,否则会出现下次点击,弹窗展示的数据依旧是上次的数据。
<script>
method:{
// 取消按钮
cancel(){
this.checkId = "";
this.textContent = "";
this.mustWriteTag = "";
this.$emit("backHandles");
},
// 确定按钮,处理逻辑
define(checkId){
if (this.currentDialogInfo.dialogType == '1'){
if(!checkId){
this.showDialog("请选择退订原因!");
return;
}
if(this.mustWriteTag == "10041001" && isNull(this.textContent)){
this.showDialog("请填写退订说明");
return;
}
// 关闭当前页面
this.$emit('backHandles');
let _this = this;
//需传入线索ID,订单号,操作类型, 驳回操作时选用户填了驳回备注也需要传入
let v = this.currentDialogInfo;
const params = {
};
_this.$dialog.loading.open("处理中");
_this.$api.retailOrder
.retailOrderPost("xxx", params)
.then((res) => {
_this.$dialog.loading.close();
let icon = "";
if (res.code == 1001) {
_this.$dialog.toast({
mes: res.message,
timeout: 1000,
icon: "success",
callback: () => {
// 处理完毕修改选项以及说明为空
this.checkId = "";
this.textContent = "";
this.mustWriteTag = "";
_this.$emit("updateDataList");
},
});
}
}).catch(() => {
// 处理完毕修改选项以及说明为空
this.checkId = "";
this.textContent = "";
this.mustWriteTag = "";
_this.$dialog.loading.close();
});
}
</script>