Vue学习
Vue学习的准备知识-HTML ,JS,CSS
Vue学习的准备知识-ES6语法
Vue学习的准备知识-原型与原型链
Vue学习的准备知识-Promise
Vue学习的准备知识-Axios
学习地址 https://axios.nodejs.cn/docs/intro 或 https://axios.js.cn/
Vue前端显示后端异常信息
cancelUser() { cancel().then((res) => { if (res.msgCd === '001' || res.msgCd === '002') { this.logout().then(() => { console.log('logout successfully', res) }) } else { // 后端错误,显示后端异常信息 this.$message.error(res.msgInfo) this.tip = false this.loading = false } }).catch(() => { this.tip = false this.loading = false }) },
Vue组件引入和使用
定义如下:
<template> ... <!-- 引入组件时,取了别名,使用时以大写字母为界[大写变小写,加-]; 别称是AModal;使用组件时为<a-modal> --> <a-modal> ... </a-modal> </template> <script> import { Modal,} from 'ant-design-vue' ... export default { // 文件名和这里的name保持一致,单词首字母都大写 name: 'OtherTips', components: { // 引入组件时,可以取别名;AModal是Modal的别称【别称在前,组件名在后】 AModal: Modal, }, props: { // 组件的属性值 otherTypeVisible: { type: Boolean, default: false, }, ... }, ... } </script>
组件使用
<template> ... <!-- 引入时组件名为OtherTypeTips,使用时如下:大写变小写,加-分割符 :other-type-visible 设置组件自己的属性值 ref 在<script></script>中使用时,渲染组件 --> <other-type-tips :other-type-visible="otherTypeVisible" ref="otherTypeTips" @cancel="cancelBus"></other-type-tips> </template> <script> import OtherTypeTips from'@/components/OtherTypeTips.vue' export default { name: 'CheckedBusForBid', components: { // 声明引入的组件 OtherTypeTips, ... }, methods: { goPay(params) { switch(params) { case '03': // 调接口传回的方式是其他 this.otherTypeVisible = true // 使用this.$refs.otherTypeTips获取到组件 // init是组件初始化,组件中有init这个方法 this.$refs.otherTypeTips.init(this.indexId) break default: this.$message.warning('请选择') break } } } ... } </script>
ant-design-vue组件库
- 页面弹出弹窗需求,ant-design-vue没有对应的Dialog弹窗组件, 使用的是AModal组件【弹窗组件】
只显示字段或隐藏
<a-col :span="12"> <a-form-item label="金额:" class="form-item left-col"> <a-input // disabled为原生属性值, :disabled为vue的属性值,可以通过js代码来控制a-input是否可填 :disabled="true" autocomplete="new" suffix="元" /> </a-form-item> </a-col>
问题及解决方案[基于Vue2
]
-
Vue中常用的属性
-
单向绑定使用: 号,比如 columns为原始元素,:columns=“fromColumns” fromColumns为JS中定义的columns
<a-table :pagination="false" :columns="fromColumns" :loading="loading" :data-source="frameData" :rowKey="(record) => record.id" bordered > </a-table>
-
双向绑定使用v-model
<a-col :span="12"> <upload // ref 绑定自己编写的helloLicense组件 ref="helloLicense" // v-model 来实现与JS中的license进行双向绑定 v-model="license" label="***" required custom-type="13" :max-size="10" :params="uploadParams" tips="支持:png,jpg,jpeg,docx,pdf,zip格式,文件大小最大为10M" > </upload> </a-col>
-
元素的属性值,要使用JS的值,要用``来包裹 或者在属性中直接用,同时,要进行单向绑定
-
js中用``包裹
// 标签如下 <a-tab-pane :tab="bidTabText"> </a-tab-pane> // js代码中如下 `hello(${this.bidData.length})`
-
在元素属性中直接使用
<a-form-item :label="`中国${list.length > 1 ? index+1 : ''}名称`"> </a-form-item>
-
-
-
在VSCode中,文件名字大小写更新之后; 重新引入会报错
- 报错信息:Already included file name …
- 报错原因: 因为文件在VSCode中已经存在并缓存了;所以报这个错误
- 解决办法: 快捷键:Ctrl + shift + P,打开:“命令面板”,输入:重新加载
-
出现eslint循环依赖的错误
-
报错信息:Dependency cycle via @/components/CheckedBusDialog:13eslintimport/no-cycle
-
报错原因: 在components下的组件,引入components的其他组件,只能一个个引入。不同同时引入多个;
import { CheckedBusForBid, CheckedBusForPerform } from '@/components'
- 解决办法: 一个个分别引入
import CheckedBusForBid from '@/components/CheckedBusForBid' import CheckedBusForPerform from '@/components/CheckedBusForPerform'
-
-
出现ESLint的简写错误
-
出现的错误: Expected property shorthand
-
错误原因:引入组件的时候,别称与组件名不能完全一致,否则会出现这个错误
-
解决方法:(1)不起别称 或(2)取一个不同名字的别称
-
-
数组循环遍历并退出循环
- 使用for循环数组,并退出【退出循环时,暂时推荐使用】
const visibleList = ['false', 'true', 'true'] for (let i = 0; i < visibleList.length; i += 1) { if (visibleList[i] === 'true') { this.visible = visibleList[i] // 退出循环 break } }
- 使用Foreach【退出循环时,暂不推荐使用此方法】
try { const visibleList = ['false', 'true', 'true'] // forEach遍历数组 visibleList.forEach((item) => { if (item === 'true') { throw new Error('false') } }) } catch (e) { if (e.message === 'false') { return } }
- 使用some
const visibleList = ['false', 'true', 'true'] visibleList.some((v) => { if (v === 'true') { return true } return true })
- 使用every
const visibleList = ['false', 'true', 'true'] visibleList.every((item) => { if (item === 'true') { this.visible = item // 退出循环 return false } return true })
-
参考文档
-
https://www.cnblogs.com/lemperor/p/17271948.html
-
https://cloud.tencent.com/developer/article/2094721
-
https://www.zhihu.com/tardis/zm/art/601625100?source_id=1005
-
Promise对象有if-else时,要在else中添加resolve(true)或reject()结束Promise对象
getBidUnpayList() { return new Promise((resolve, reject) => { if (this.getRegisterResource === '01') { this.loading = true unPayListQuery(this.getEgId).then((res) => { if (res.waitPaymentList.length > 0) { this.bidUnpayData = res.waitPaymentList this.data = res.waitPaymentLists this.loading = false this.visibleList.push(true) } else { this.visibleList.push(false) this.loading = false this.$store.commit(REMOVE_EGID) } // 用resolve结束 resolve(true) }).catch((error) => { reject(error) console.log('获取失败', error) this.loading = false this.visibleList.push(false) this.$store.commit(REMOVE_EGID) }) } else { // else中也利用resvole结束掉 resolve(true) } }) }
-
利用Promise.all同步接口调用
Promise.all([ // 获取bid待办列表1 this.getBidUnpayList(), // 获取待办列表2 this.getPerformUnpayList(), // 获取待办列表3 this.getFrameUnpayList(), ]).then((res) => { // 设置投标bid tab的数据 this.bidData = this.bidUnpayData // 设置bid tab显示文本 this.bidTabText = this.bidData ? `投标(${this.bidData.length})` : 0 // 设置perform tab的数据 this.performData = this.performUnpayData // 设置perform tab显示文本 this.performTabText = this.performData ? `履约(${this.performData.length})` : 0 // 设置frame tab的数据 this.frameData = this.frameUnpayData // 设置frame tab的显示文本 this.frameTabText = this.frameData ? `年度(${this.frameData.length})` : 0 // 获取弹窗最终显示与否 for (let i = 0; i < this.visibleList.length; i += 1) { if (this.visibleList[i] === 'true' || this.visibleList[i] === true) { this.visible = this.visibleList[i] break } } })
-
ant-design-vue 是用Tab-Pane,属性tab显示js的内容。可以用:tab(单向绑定,tab是tab-pane的原属性;:tab就变成了vue的属性,实现单向绑定)
注:标签属性中,需要用到JS中的动态数据和属性,都可以使用:属性名="JS代码"的形式,在JS中使用
js代码
来包裹js代码-
vue template中的代码为: :tab=“bidTabText”
<!--default-active-key 指定默认的显示tab,:tab="bidTabText" 单向绑定js代码--> <a-tabs default-active-key="bid" @change="checkBidTab"> <a-tab-pane key="bid" :tab="bidTabText"> <checked-bus-for-bid :check-visible="checkVisible" :bidData="bidData" ref="checkedBusForBid" @handleVisible="handleVisible"> </checked-bus-for-bid> </a-tab-pane> ... </a-tabs>
-
vue script中的代码
// 设置bid tab显示文本,使用``来包括js代码 this.bidTabText = this.bidData ? `投标(${this.bidData.length})` : 0
-
-
保存或者提交, 校验数据,如果没有,则报错;不进行保存或提交;使用return;
methods:{ handleSave(){ ... const tempContractList = this.contractList.filter( (item) => item && item.contractName) if (tempContractList.length === 0) { // 页面弹出错误信息 this.$message.error('合同名称不能为空') // 结束handleSave方法 return } } }
-
ant-design-vue 1.0(适用于vue 2.0版本),在form表单中,使用v-for遍历list,并且用到了a-input标签,在a-input中无法同时使用v-model(双向绑定), v-decorator(双向绑定,校验信息);因为有必填校验,因此,最终使用v-decorator,不使用v-model; 但list无法回显。最终解决如下:
-
先在data()中定义list的初始值,不然,页面不能显示
// 合同名称List contractList: [{ contractName: undefined, }],
-
在template中的form中,遍历contractList, 用div元素,包裹元素
<div v-for="(item, index) in contractList" :key="index"> <a-row> <a-form-item // custom-horizontal-layout 来控制当前<a-form-item>为水平布局 class="custom-horizontal-layout left-col" // 这样显示合同名称1:`` 包裹 :label="`合同名称${index+1}:`" > <a-input // :disabled, 利用vue函数来控制是否只读或可以输入 :disabled="disabledByAppKey()" class="form-item" // 对输入的值,进行处理【index表示list下标,$event表示输入的事件】 @input="handleInputChange(index, 'contractName', $event)" // `contractList[${index}].contractName` 来表示唯一性,使用`${index}`也能表示唯一性; rules.contractNameCheck,在rules中定义的contractNameCheck的rule规则 v-decorator="[`contractList[${index}].contractName`, rules.contractNameCheck]" /> // 添加合同的图标元素 通过@click来监听事件,添加合同名称 <a-icon type="plus-circle" style="margin-left: 22px; font-size: 25px" @click="addContract()"/> // 删除合同的图标元素 通过@click来监听事件,删除合同名称 <a-icon // 当元素数量大于1时,才显示删除图标 v-if="index>0" type="minus-circle" style="margin-left: 11px; font-size: 25px" @click="delContract(index)" /> </a-form-item> </a-row> </div>
注:
:disabled(单向绑定),来控制是否可以输入;@input(event事件监听),来处理输入的值
v-decorator(双向绑定)来进行对元素进行校验处理;
-
在rules中添加contractNameCheck的rule。 rules是放在data()中,
data(){ return { rules: { // 引入的公共rules ...rules, contractNameCheck: { rules: [ { required: true, message: '请输入合同名称' }, ], // 公共的rule(引入使用),类似trigger:blur,内容如下: // export const commonInputRule = { // validateTrigger: 'blur', // validateFirst: true,} ...commonInputRule, }, } } }
-
在methods方法中,添加disabledByAppKey(),handleInputChange(index, ‘contractName’, $event),addContract(),delContract()等方法
methods: { ... // 通过appKey控制disable disabledByAppKey() { return this.appKey ? !(this.appKey === '***') : false }, // 增加合同名称 addContract() { if (this.contractList.length > 2) { this.$message.error('最多只能添加3个合同名称') return } // push 添加对象 this.contractList.push({ contractName: undefined }) // 通过setFieldsValue把list赋值给template要遍历的contractList this.form.setFieldsValue({ contractList: this.contractList }) }, // 删除合同名称 delContract(index) { if (this.contractList.length > 1) { // splice通过index删除list中的对象 this.contractList.splice(index, 1) // 通过setFieldsValue把list赋值给template要遍历的contractList this.form.setFieldsValue({ contractList: this.contractList }) } }, // 合同名称输入框值改变 handleInputChange(index, field, event) { // field表示传入的属性值,通过event事件,event.target.value来获取输入的值 this.contractList[index][field] = event.target.value }, }
-
保存之后,点击编辑进来,要回显数据,要遍历并通过const obj,挨个设置【重点】
-
watch监听数据变化
watch:{ info:{ handler(val){ // $nextTick表示立即钓调用,this.setInfo为方法 if(val) this.$nextTick(()=>this.setInfo(val)) } // 立即渲染 immediate: true, // 进深渲染 deep: true, } }
-
在methods的setInfo方法中
setInfo(detail){ // 设置合同名称 if (detail.contractNameList) { // detail.contractNameList为List<String>的list,把list转化为是对象类型的JS数组,使用map this.contractList = detail.contractNameList.map((item) => ({ contractName: item })) // 要使用this.$nextTick,立即执行。 this.$nextTick(() => { // 遍历js的list, 不能直接设置,如: // this.form.setFieldsValue({contractList, this.contractList}),这样的话,只会显示第一条数据 this.contractList.forEach((item, index) => { const obj = {} // 采用如下方式,根据下标设置每个值,才能获取所有的list的数据 obj[`contractList[${index}]`] = this.contractList[index] this.form.setFieldsValue(obj) }) }) } }
-
-
显示结果如下:
-
-
如果column前面添加必填的红色*号,但子元素不是input输入框的话,可以使用新样式来解决
-
template中的代码如下:
<a-row> <a-col :span="12"> <!-- label-required 是用来显示红色 * 号 --> <a-form-item label="名称1:" class="form-item left-col label-required"> <p class="content">{{ name2 }}</p> </a-form-item> </a-col> <a-col :span="12"> <a-form-item label="名称2:" class="form-item label-required"> <p class="content">{{ name2 }}</p> </a-form-item> </a-col> </a-row>
-
在页面用element找到element找到对应的元素和对应的style信息
-
在style中添加红色的*号样式
// /deep/ 表示二级元素,要用这个 /deep/ .label-required { // ::before表示在之前,添加样式 .ant-form-item-label label::before { display: inline-block; margin-right: 4px; color: #f5222d; font-size: 14px; font-family: SimSun, sans-serif; line-height: 1; content: '*'; } }
-
调整之后,效果如上图的截图的名称2一样
-
如果想在元素之前添加红色*号,因为不是二级元素,不用/deep/
.span-required::before { display: inline-block; margin-right: 4px; color: #f5222d; font-size: 14px; font-family: SimSun, sans-serif; line-height: 1; content: '*'; }
-
-
父组件与之组件之间进行单向数据传递
-
父组件引入子组件
<script> import PerformDialog from '@components/PerformDialog' export default{ name: "Dialog" components: { PerformDialog, }, data() { return { performData: [] } } } </script>
-
父组件通过 :performData 传递数据给子组件
<a-tab-pane key="peformance" :tab="performTabText"> <perform-dialog :performData="performData" ref="performDialog"></perform-dialog> </a-tab-pane>
-
在子组件中的props中,定义performData,接收来自父组件的数据
export default { name:"PerformDialog" ... props: { performData:{ type: Array, default() { return [] }, } } }
-
-
父组件与子组件之间进行双向数据传递
-
和上面一样,首先引入子组件;
-
在父组件使用子组件的时候,传入值;【使用visible属性;父组件创建事件监听@handleVisible=“handleVisible” handleVisible来处理子组件传回的visible值】
<a-tab-pane key="peformance" :tab="performTabText"> <perform-dialog :visible="visible" @handleVisible="handleVisible" ref="performDialog"></perform-dialog> </a-tab-pane>
-
父组件创建的handleVisible方法
methods: { ... // 接收子组件visible的值,并控制父组件弹窗是否显示 handleVisible(value) { if (value === false) { this.visible = value } }, }
-
子组件接收父组件传入的值,
export default { name:"PerformDialog" ... props: { visible: { type: Boolean, default: false, }, } }
-
并利用this.$emit()方法处理,传回更改之后的值给父组件
methods: { busiHandle(record) { ... if(record){ this.visible = false // handleVisible父组件定义的监听事件 this.$emit('handleVisible', this.visible) } } }
-
子组件接收父组件传入的值,
export default { name:"PerformDialog" ... props: { visible: { type: Boolean, default: false, }, } }
-
并利用this.$emit()方法处理,传回更改之后的值给父组件
methods: { busiHandle(record) { ... if(record){ this.visible = false // handleVisible父组件定义的监听事件 this.$emit('handleVisible', this.visible) } } }
-