一、i18n国际化切换

【粗暴直接】如果国际化切换涉及的手动修改太多,干脆切换语言的时候直接刷新页面重新渲染算了,以下都是不刷新页面的方法

1. data中的数据

data中的数据初始化一次之后,不手动修改是不会变化的,所以直接在 data中使用this.$t('xxx'),只有页面首次加载是有效的,中途切换的话,是没办法跟着切换的。
解决方法 1: 将需要用到国际化的数据定义在computed里面

<template>
	<div>
		<ul>
			<li v-for="data in list">{{ data.name }}</li>
		</ul>
	</div>
</template>
<script>
export defaut {
	computed: {
		list() {
			return [
				{name: this.$t('common.title1')},
				{name: this.$t('common.title2')},
				{name: this.$t('common.title3')}
			]
		}
	}
}
</script>

解决方法 2: 在 data中的属性值定义为国际化对应的key,在 template中使用{{ $t(key) }}的方式来引用

<template>
	<div>
		<ul>
			<li v-for="data in list">{{ $t(data.name)}}</li>
		</ul>
	</div>
</template>
<script>
export defaut {
	data() {
		return {
			list: [
				{name: 'common.title1'},
				{name: 'common.title2'},
				{name: 'common.title3'}
			]
		}
	}
}
</script>
// zh_CN.json
{
	"common": {
		"title1": "标题1",
		"title2": "标题2",
		"title3": "标题3"
	}
}

2. echarts图表中的相关元素

2.1 轴坐标单位

在 watch中监听 '$i18n.locale',在语言切换时,重新配置 option,使用 setOption()方法。
(此方法对于echarts中所有配置项都适用,但是过于繁琐,有些配置项没有必要使用,比如有 formatter属性的配置项,可以对 formatter使用回调函数形式)

<script>
export defaut {
	data() {
		return {
			myChart: null,
			option: null,
		}
	},
	watch: {
		'$i18n.locale'(newValue) {
			// 设置 option参数
			this.option.series[0].data,forEach( data => {
				data.tooltip.formatter = `${this.$t('common.tipTitle')}<br/>
						${this.$t('common.tipName')}: ${data.value}`;
			})
			this.option.series[0].markLine.tooltip.formatter = `${this.$t('common.tipAverage')}</br>
					${this.$t('common.tipContent')}: {c}`;
			// 使用 setOption()方法重绘
			this.myChart.setOption(this.option)
		}
	}
}
</script>

2.2 各种 tooltip

不管是全局的 tooltip,还是 series中单独定制的,(markline在官网中没有提供 tooltip属性,但是我添加生效了。。。)tooltip中的 formatter属性均使用回调函数形式,即可实现国际化自动切换

<script>
let option = {
	tooltip: {
		// 使用箭头函数,否则取不到 this
		formatter: (params) => {
			return `${this.$t('common.tipTitle')}<br/>
				${this.$t('common.tipName')}: ${params.name}`;
		}
	}
}
</script>

2.3 legend

legend的数据需要与 series的数据中的 name保持一一对应的关系,可以将这两处都传入国际化对应的 key,在 legend.formatterseries.label.formatter使用回调函数的形式返回国际化处理后的显示值
有个问题:在语言切换时,需要点击一个图例才会触发legendseries的切换,所以还是需要通过 watch监听,手动触发一下 setOption(),不需要重新设置配置项

<script>
export defaut {
	data() {
		return {
			myChart: null,
			option: null,
		}
	},
	mounted() {
		let key = 'common.type.';
		let legendData = [
			`${key}type1`,
			`${key}type2`,
			`${key}type3`,
			`${key}type4`,
		];
		let seriesData = [
			{ value: 0, name: `${key}key1` },
			{ value: 0, name: `${key}key2` },
			{ value: 0, name: `${key}key3` },
			{ value: 0, name: `${key}key4` }
		];
		this.option = {
			legend: {
				orient: 'vertical',
          		left: 'left',
          		data: legendData,
          		formatter: (params) => {
		            return this.$t(params);
	            }
			},
			series: [{
				data: seriesData,
				type:'pie',
				radius: '60%',
       			center: ['60%', '60%'],
          		label: {
            		normal: {
              			formatter: (params) => {
                			return this.$t(params.name);
              			}
            		}
          		}
			}]
		}
		this.myChart.setOption(this.option);
	},
	watch: {
		'$i18n.locale'(newValue) {
			// 不需要重新设置配置项,只需要手动触发一下setOption()
			this.myChart.setOption(this.option)
		}
	}
}
</script>

3. iView框架中的组件

3.1 table表格

  • 表头
    data中定义表头时,在 renderHeader回调函数中定义表头显示内容
data () {
    return {
      column: [{
          key: 'name',
          renderHeader: (h, params) => {
            return h('strong', this.$t('common.name'));
          }
        },
        {
          key: 'age',
          renderHeader: (h, params) => {
            return h('strong', this.$t('common.age'));
          }
        },
        {
          key: 'gender',
          renderHeader: (h, params) => {
            return h('strong', this.$t('common.gender'));
          }
        }]
    }
  }

二、echarts中遇到的问题

1. 使柱形图、折线图等尽量占满整个 canvas(设置 grid

grid: {
	top: "40",  // 预留y轴单位的展示空间
	left: "40",  // 预留y轴刻度数值的展示空间
	right: "40",  // 预留x轴单位的展示空间
	bottom: "30" // 预留x轴类目名称的展示空间
 }

2. 将 echarts图表放在 Tab中切换展示时,图表渲染不出来

问题原因: Tab一开始是隐藏的,没有宽高,echarts在初始化时,没有获取到宽高导致图表显示不出来
解决方法: 每次设置完 option调用 setOption()之后,再手动调用一下 resize()方法,或者每次都重新执行 echarts.init()setOption()

3. setOption()第三个参数设置为 true,报错了:[Vue warn]: Error in nextTick: “TypeError: Cannot read property ‘count’ of undefined”


三、 iView中遇到的问题

1. 内置的图标不显示

问题原因: webpack中配置了 url-loader来处理字体文件,大小低于limit属性限制的资源被转换成了 Base64
解决方法: 将这个 limit设置为一个比较小的值
在这里插入图片描述

2. 子组件(包括后代多层子组件)中的 Tabs标签渲染到了父组件上

**问题原因:**嵌套的 Tabs标签需要在 Tabs中指定 name 属性来区分层级,在 TabPane 中设置 tab 属性指向对应 Tabsname 字段。

<!-- 父组件 -->
<template>
	// 在 Tabs上设置 name属性
	<Tabs name="tab1" type="card" @on-click="tabChange">
		// 在 TabPane上设置 tab属性
		<TabPane :label="'标签1'" name="overview" tab="tab1">
			// 子组件
			<my-component></my-component>
		</TabPane>
		<TabPane  :label="'标签2'" name="transport" tab="tab1">

		</TabPane>
			</Tabs>
</template>
<!-- 子组件 -->
<template>
	// 在 Tabs上设置 name属性
	<Tabs name="tab2" type="card" @on-click="tabChange">
		// 在 TabPane上设置 tab属性
		<TabPane :label="'标签1.1'" name="flow" tab="tab2"></TabPane>
		<TabPane  :label="'标签1.2'" name="speed" tab="tab2"></TabPane>
	</Tabs>
</template>

3. TabPane高度不够,最下方的 Page分页器的每页条数下拉选项框被挡住

问题原因: .ivu-tabs设置了 overflow: hidden
解决方法: 将分页器的 placement属性设置为 top,下拉选项框就会在分页器上方展开
更新: 其他一些下拉框也会被挡住,比如作为查询条件的下拉框,直接在 css中设置 overflow: visible !important;覆盖,暂时不知道这样会有什么问题

<!-- 自己封装的一个简单的带分页器的 table -->
<template>
  <div>
    <Table 
      stripe 
      :max-height="maxHeight" 
      :columns="columns" 
      :data="tableData"
      @on-selection-change="selectionChange" />
    <div class="clearfix" style="margin: 10px;">
      <div style="float: right;">
        <Page 
          :total="pagination.total" 
          :current="pagination.current" 
          :page-size="pagination.size"
          :placement="placement"
          size="small" 
          show-elevator 
          show-sizer 
          @on-change="changePage" 
          @on-page-size-change="changePageSize" />
      </div>
    </div>
  </div>
</template>
  props: {
    placement: {
      type: String,
      default () {
        return 'top'
      }
    }
  },

4. Modal的确定按钮点击之后直接就关闭了弹窗,实际还有其他的操作,比如 Form表单验证,或者后台请求,需要根据结果判断是否可以关闭弹窗

解决方法: 参考官方文档中 “异步关闭” ,给Modal添加属性loading后,点击确定按钮对话框不会自动消失,并显示 loading 状态,需要手动关闭对话框,常用于表单提交。

<!-- 自己封装的一个简单的带分页器的 table -->
<template>
  <div>
    <Modal 
      v-model="modalhowFlag" 
      :loading="modalLoading"
      :title="xxx" 
      :ok-text="保存'" 
      @on-ok="executeSaving" 
      width="60%">
      <From ref="formValidate" :rules="ruleValidate">
      	...
      </From>
    </Modal>
  </div>
</template>
methods: {
  executeSaving() {
	this.$refs.formValidate.validate((valid) => {
      // 数据校验
      if (valid) {
	    // 发送请求
		axios({...}).then(res => {
		  if (res.data.status == 'ok') {
		  	this.$Message.success('Success!');
		  	this.$emit('savingHandle', true);
		  } else {
		  	this.$Message.error('Fail!');
		  	this.$emit('savingHandle', false);
		  }
		}).catch(err => {
		  this.$Message.error('Fail!');
		  this.$emit('savingHandle', false);
		})
      } else {
		this.$Message.error('Fail!');
		this.$emit('savingHandle', false);
      } 
	}
  },
  // 保存结果
  savingHandle(flag) {
    // console.log(valid)
    // 关闭 确定按钮的 loading
    this.modalLoading = false;
    if (flag) {
      // 保存成功,关闭 Model
      this.createShowFlag = false;
    }
  }
},

5. Form表单对数字进行必填+格式校验

问题现象: 同时添加 必填 和 正则校验时,如果输入非数字,会提示必填。
解决思路1-实现有问题,只是记录一下,以后面的解决方法为准: 将“格式”校验写在“必填”校验之前,并且两者都要指定 type:number,并且 <Input>也要指定 number类型—— 页面无法显示必填标识*

<template>
  <Form ref="createForm" :model="newObj" :rules="ruleValidate" :label-width="150">
    <FormItem label="xx号码" prop="xxNumber">
      <Input v-model="newObj.xxNumber" number/>
    </FormItem>
  </Form>
</template>
computed: {
  ruleValidate() {
    return {
      asNumber: [
      	// xxNumberPattern是自定义的正则
        { type: 'number', pattern: xxNumberPattern, message: '格式不正确。', trigger: 'blur' },
        { type: 'number', required: true, message: '该字段为必填。', trigger: 'blur' }
      ]
    }
  }
}

解决方法: <Input>仍然默认 text类型,“必填”校验使用默认方式,不指定number,“格式”校验需要自定义

<template>
  <Form ref="createForm" :model="newObj" :rules="ruleValidate" :label-width="150">
    <FormItem label="xx号码" prop="xxNumber">
      <Input v-model="newObj.xxNumber" />
    </FormItem>
  </Form>
</template>
computed: {
  ruleValidate() {
    return {
      asNumber: [
        { required: true, message: '该字段为必填。', trigger: 'blur' },
        { validator: this.xxNumberFormatValidate, trigger: 'blur' }
      ]
    }
  }
},
methods: {
  xxNumberFormatValidate(rule, value, callback) {
  	// xxNumberPattern是自定义的正则
    if (!xxNumberPattern.test(value)) {
      callback('格式不正确。');
    } else {
      callback();
    }
  }
}

6. Form表单结构相同的<FormItem>根据条件切换,切换后原先条件下的<FormItem>的校验报错信息仍然显示在页面上

问题原因: 根据 vue的渲染规则,切换条件会复用原先的 <FormItem>组件的 dom,只更新其中的数据,导致原先校验的报错信息还会保留在页面上
解决方法: 给不同条件下的 <FormItem>添加不同的 key

<template>
  <Form ref="configForm" :model="config" :rules="ruleValidate" :label-width="150">
      <FormItem label="选择条件" prop="condition">
        <Select v-model="config.condition">
          <Option v-for="o in conditionOptions" :value="o.id" :key="`o-${o.id}`">{{ o.name }}</Option>
        </Select>
      </FormItem>
      <!-- 如果不加 key的话,条件1的情况下,“选择设备”的 FormItem 报错而不纠正的情况下直接切换成条件2,根据 Vue的渲染原则,这个 FormItem的 dom会被“选择A端设备”所复用,原先的报错信息因为没有被纠正而保留在页面上  -->
      <FormItem label="选择设备" prop="deviceIds" v-if="config.condition == 1" key="device">
        <CheckboxGroup v-model="config.deviceIds">
          <Checkbox v-for="o in deviceList" :label="o.id" :key="`o-${o.id}`">{{ o.name }}</Checkbox>
        </CheckboxGroup>
      </FormItem>
      <FormItem label="选择A端设备" prop="deviceAIds" v-if="config.condition == 2" key="deviceA">
        <CheckboxGroup v-model="config.deviceAIds">
          <Checkbox v-for="o in deviceAList" :label="o.id" :key="`o-${o.id}`">{{ o.name }}</Checkbox>
        </CheckboxGroup>
      </FormItem>
      <FormItem label="选择B端设备" prop="deviceBIds" v-if="config.condition == 2" key="deviceB">
        <CheckboxGroup v-model="config.deviceBIds">
          <Checkbox v-for="o in deviceBList" :label="o.id" :key="`o-${o.id}`">{{ o.name }}</Checkbox>
        </CheckboxGroup>
      </FormItem>
    </Form>
</template>
computed: {
  ruleValidate() {
    return {
      condition : [
            { type: 'number', required: true, message: '请选择条件', trigger: 'change' }
          ],
          deviceIds: [
            { type: 'array', required: true, message: '请选择设备', trigger: 'change' }
          ],
          deviceAIds: [
            { type: 'array', required: true, message: '请选择A端设备', trigger: 'change' }
          ],
          deviceBIds: [
            { type: 'array', required: true, message: '请选择B端设备', trigger: 'change' }
          ]
    }
  }
}
Logo

前往低代码交流专区

更多推荐