目录

【问题描述】

【问题摘要】 

【分析问题】

 【完整Test代码】

【封装自定义指令】


↑↑↑↑↑↑↑↑↑↑↑↑ 不想看解决问题过程的可点击上方【封装自定义指令】目录直接跳转获取结果即可~~~

 

【问题描述】

        一位朋友遇到这么一个开发场景:在表格里面嵌入el-select组件,每次修改值后,失去焦点时将修改值提交后台保存,但是发现在el-select组件失去焦点时,blur事件的evt.target.value值总为前一次选择的值;

【问题摘要】 

1、el-select组件失去焦点时需要获取组件当前值而不是上一次的值;

2、el-select组件切换选项时不提交后台,只有当组件失去焦点后才提交当前值;

【分析问题】

        一刚开始以为是下拉框收起动画延时问题导致内部value值被延时修改,所以就在blur事件里延时获取evt.target.value,貌似没问题了

blurHandler(evt){
	setTimeout(() => {
		console.log(evt.target.value);
	},250)
},

随后又发现通过@blur绑定事件只会触发一次,好吧那就加修饰符吧:@blur.capture.native,好像解决只触发一次的问题了

 

<el-select v-model="value" @blur.capture.native="nativeBlurHandler" ref="select">
	<el-option
	  v-for="item in options"
	  :key="item.value"
	  :label="item.label"
	  :value="item.value">
	</el-option>
</el-select>

但是随之而来的问题就是,每次切换取值后都会触发一次blur事件,这可不是我们想要的,这不变成change事件了吗?继续深挖!

那就打印一下this.$refs.select看看吧,找到this.$refs.select.$data, 看里面有定义啥变量没,发现了如下变量:

 

log(eventName){
	let {
		createdSelected,
		inputHovering,
		isOnComposition,
		isSilentBlur,
		menuVisibleOnFocus,
		softFocus,
		visible
	} = this.$refs.select.$data;
	
	console.table([
		{
			name: eventName,
			value: '',
		},
		// {
		// 	name: 'createdSelected',
		// 	value: createdSelected
		// },
		{
			name: 'inputHovering',
			value: inputHovering
		},
		// {
		// 	name: 'isOnComposition',
		// 	value: isOnComposition
		// },
		{
			name: 'isSilentBlur',
			value: isSilentBlur
		},
		// {
		// 	name: 'menuVisibleOnFocus',
		// 	value: menuVisibleOnFocus
		// },
		// {
		// 	name: 'softFocus',
		// 	value: softFocus
		// },
		{
			name: 'visible',
			value: visible
		},
	])
}

 通过反复测试发现只有inputHovering,isSilentBlur,visible这三个变量与el-select组件focus,blur事件有关联:

 通过上图可以发现,只有最下方的失去焦点事件才是我们想要的,此时visible==false,isSilentBlur==true,正好满足我们的判断条件,于是blur事件改造成这样了:

 

nativeBlurHandler(evt){
	console.log('nativeBlurHandler', {...this.$refs.select});
	let {
		isSilentBlur,
		visible
	} = this.$refs.select;
	if( isSilentBlur  && !visible ) {
		console.log('提交', this.$refs.select.selected.currentValue);
	}
	this.log('blur事件');
},

又因为value取值从evt.target.value获取的不是实时的,也就是值不正确,继续深挖,发现this.$refs.select.selected.currentValue就是我们想要的正确的值,于是乎,问题就解决了!测试demo完整代码如下:

 【完整Test代码】

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<!-- import CSS -->
		<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
	</head>
	<body>
		<div id="app">
			<el-select v-model="value" placeholder="请选择" @blur="blurHandler" @blur.capture.native="nativeBlurHandler" ref="select">
			    <el-option
			      v-for="item in options"
			      :key="item.value"
			      :label="item.label"
			      :value="item.value">
			    </el-option>
			</el-select>
		</div>
	</body>
	<!-- import Vue before Element -->
	<script src="https://unpkg.com/vue@2/dist/vue.js"></script>
	<!-- import JavaScript -->
	<script src="https://unpkg.com/element-ui/lib/index.js"></script>
	<script>
		let selectElm;
		new Vue({
			el: '#app',
			data: function() {
				return {
					options: [{
					  value: '黄金糕',
					  label: '黄金糕'
					}, {
					  value: '双皮奶',
					  label: '双皮奶'
					}, {
					  value: '蚵仔煎',
					  label: '蚵仔煎'
					}, {
					  value: '龙须面',
					  label: '龙须面'
					}, {
					  value: '北京烤鸭',
					  label: '北京烤鸭'
					}],
					value: ''
				}
			},
			methods: {
				focusHandler(evt){
					this.log('focus事件');
				},
				blurHandler(evt){
					setTimeout(() => {
						console.log(evt.target.value);
					},250)
				},
				nativeBlurHandler(evt){
					console.log('nativeBlurHandler', {...this.$refs.select});
					let {
						isSilentBlur,
						visible
					} = this.$refs.select;
					if( isSilentBlur && !visible ) {
						console.log('提交', this.$refs.select.selected.currentValue);
					}
					this.log('blur事件');
				},
				log(eventName){
					let {
						createdSelected,
						inputHovering,
						isOnComposition,
						isSilentBlur,
						menuVisibleOnFocus,
						softFocus,
						visible
					} = this.$refs.select.$data;
					
					console.table([
						{
							name: eventName,
							value: '',
						},
						// {
						// 	name: 'createdSelected',
						// 	value: createdSelected
						// },
						{
							name: 'inputHovering',
							value: inputHovering
						},
						// {
						// 	name: 'isOnComposition',
						// 	value: isOnComposition
						// },
						{
							name: 'isSilentBlur',
							value: isSilentBlur
						},
						// {
						// 	name: 'menuVisibleOnFocus',
						// 	value: menuVisibleOnFocus
						// },
						// {
						// 	name: 'softFocus',
						// 	value: softFocus
						// },
						{
							name: 'visible',
							value: visible
						},
					])
				}
			}
		})
	</script>
</html>

【封装自定义指令】

想到给组件添加ref实际并不是那么好用且麻烦,所以我又将其封装成了指令,指令代码及用法如下,大家随取随用哈↓↓↓↓↓↓

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<!-- import CSS -->
		<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
	</head>
	<body>
		<div id="app">
			<el-row>
				<el-col :span="24">
					<el-select v-select-blur="selectBlurHandler" v-model="value">
						<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
						</el-option>
					</el-select>
				</el-col>
			</el-row>
		</div>
	</body>
	<!-- import Vue before Element -->
	<script src="https://unpkg.com/vue@2/dist/vue.js"></script>
	<!-- import JavaScript -->
	<script src="https://unpkg.com/element-ui/lib/index.js"></script>
	<script>
		Vue.directive('select-blur', {
			bind: function(el, binding, vnode) {
				const selectComponent = vnode.componentInstance;
				if( selectComponent.$options.name === 'ElSelect' ) {
					selectComponent.$watch('visible', (n,o) => {
						const {
							isSilentBlur,
							visible,
						} = selectComponent;
						if(isSilentBlur && !visible) {
							selectComponent.handleBlur();
						}
					})
					selectComponent.$on('blur', () => {
						let {
							visible,
							selected: {
								currentValue
							}
						} = selectComponent;
						if (!visible) {
							binding?.value && typeof binding.value === 'function' && binding.value(currentValue);
                            selectComponent.blur();    //处理页面频繁聚焦失焦导致重复触发blur事件的问题
						}
					}, true);
				}
			},
			unbind: function(el, binding, vnode) {
				const selectComponent = vnode.componentInstance;
				if( selectComponent.$options.name === 'ElSelect' ) {
					selectComponent.$off('blur');
				}
			}
		});

		const app = new Vue({
			el: '#app',
			data: function() {
				return {
					options: [{
						value: '黄金糕',
						label: '黄金糕'
					}, {
						value: '双皮奶',
						label: '双皮奶'
					}, {
						value: '蚵仔煎',
						label: '蚵仔煎'
					}, {
						value: '龙须面',
						label: '龙须面'
					}, {
						value: '北京烤鸭',
						label: '北京烤鸭'
					}],
					value: ''
				}
			},
			methods: {
				selectBlurHandler(val) {
					console.log('提交', val);
				},
			}
		})
	</script>
</html>

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐