uni-app开发日志[20220513]:官方、第三方组件开发问题(vue3版本为主)

20 篇文章 0 订阅

一、基础

父组件调用子组件方法和变量

父组件页面内设置自定组件,并且标记好ref,方法里通过ref来调用子组件内方法和变量。

<test-input ref="zujian" />

...
this.$refs.zujian.getList(this.$refs.zujian.nextPage);
...

子组件内可被调用的变量和方法分别存放在data()methods中。

export default{
	data(){
		return {
			nextPage:19
		}
	},
	methods:{
		getList(page){
			...
		}
	}
}

子组件内不能使用onLoad等页面级方法

  1. onLoad
    onLoad 指的是页面加载,组件内只能使用 mounted 来代替实现。

  2. onPullDownRefreshonReachBottom
    很奇怪,目前vue3版本小程序里是可以使用的,h5页面不能使用。
    在父页面中给组件命名,当页面的on方法执行时调用组件内部的方法

<test-input ref="objectFormName"></test-input>

...
onPullDownRefresh() {
	this.$refs.objectFormName.resetList();
},
onReachBottom: function() {
	this.$refs.objectFormName.getList(this.$refs.objectFormName.nextPage);
},

uni-app组件下拉刷新


重新渲染组件

如果组件内部没有使用watch监听参数变化来修改数据调用;那么就在父页面给参数新赋值后重新渲染父组件。

<test-input v-if="isRe" />
<button @click="getList" :param="params" />

//变量
data(){
	return {
		isRe:true,
		params:{}
	}
}

//methods中的方法
getList:function(index){
	this.params = {page:3};
	//重新渲染组件
	this.isRe= false;
	this.$nextTick(() => {
		this.isRe= true;
	})
}

自定义组件中json格式的props不能直接赋值给data(){}中的内部变量

如果在父页面直接赋值,自定义组件中正常

// 页面
<template>
	<view>
		<uni-bug title="tt" :detail="dd"></uni-bug>
	</view>
</template>
<script>
	export default {
		data() {
			return {
				tt:'测试',
				dd:{a:1,b:2}
			}
		},
		onLoad(options) {
			//options假设为{x:-1,y:-2,t:'调试'}
			this.tt = options.t;
			this.dd = options;
		}
	}
</script>
  • props如果为String等类型,在子组件中赋值正常,
  • props如果为Object等类型,在h5正常,微信小程序失败。

具体情况及解决办法如下:

// 子组件
export default {
		name: 'uni-bug',
		props: {
			title:{
				type:String,
				default:""
			},
			detail:{
				type:Object,
				default:{}
			},
		},
		data() {
			return {
				t:this.title,//全平台正常
				r1:this.detail,//本处赋值json,在h5正常,但微信小程序中失败,r1的值始终为{a:1,b:2}
			}
		},
		computed:{
			r2:function(){
				//可能当值为json时,vue会延后处理,变成了类似异步
				//所以这里利用计算computed,让r2一直跟踪detail即可解决
				return this.detail;
			}
		},
		mounted(){
			this.show();
		},
		method:{
			show(){
				console.log(this.t);  //获取成功,显示:调试
				console.log(this.r1); //获取失败,显示:{a:1,b:2}
				console.log(this.r2); //获取成功,显示:{x:-1,y:-2,t:'调试'}
			}
		}
}

参考:Vue核心知识:computed、methods和watch的区别

原理:单向数据流 【注意在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变变更这个对象或数组本身将会影响到父组件的状态。】

data(){}是一次性的,渲染完成就结束,而computed有监控性质,非常重要,下一条问题两个页面的子组件如何传递参数也需要利用computed


父子组件双向通讯之v-model

v-model是语法糖,默认情况下在vue2和vue3分别绑定inputmodelValue的值。

//子组件的属性
// #ifdef VUE3
modelValue: {
	type: [Array, Object],
	default () {
		return []
	}
},
// #endif
// #ifndef VUE3
value: {
	type: [Array, Object],
	default () {
		return []
	}
},
// #endif

//上面是属性,可以由父组件传给子组件
//--------------------------------
//下面是用事件修改父组件的值

//子组件的某个方法中修改值
let newData = 5;
//将值回传给父组件
// #ifdef VUE3
this.$emit('update:modelValue', newData)
// #endif
// #ifndef VUE3
this.$emit('input', newData)
// #endif

下一个问题《子组件不要在本地尝试修改props值》将使用本例中的语法糖


子组件不要在本地尝试修改props值

在子组件内可以直接调用参数 this.title ,但本地直接修改props的话会提示该参数不存在,官网把其定义为 单向数据流

<!-- 父组件 -->
<template>
    <view>
        <componentA title="标题"></componentA>
    </view>
</template>
//====================
<!-- 子组件componentA -->
<template>
    <view>
        <view>{{myTitle}}</view>
    </view>
</template>
<script>
    export default {
        props: ['title'],
        data() {
            return {
                myTitle:this.title
            }
        },
        methods: {
			updateTitle() {
				this.myTitle = '修改'; // 正确
				this.title = '修改'; //错误
			}
		}
    }
</script>

真要直接修改也可以,使用方法暴露给父页面,利用父页面中方法将其值改变,参考 uniapp在子组件中修改父组件中的值

也可以利用this.$emit('update:modelValue','abcdefg')方法直接在子组件中实现,使用时请注意代码示例中的注释:

<!-- 父组件 -->
<template>
    <view>
    	<!-- 此处v-model不可缺少 -->
        <componentA v-model:returnValue="abc"></componentA>
    </view>
</template>
//====================
<!-- 子组件componentA -->
//如果增加了update:returnValue,那么就必须把update:modelValue和input加上,否则相当于this.emits被覆盖了,从而产生其它错误
emits:['update:modelValue','input','update:returnValue'],
props: {
	// #ifdef VUE3
	modelValue: {
		type: String,
		default () {
			return '';
		}
	},
	// #endif
	// #ifndef VUE3
	value: {
		type: String,
		default () {
			return '';
		}
	},
	// #endif
	returnValue: {
		type: [String,Array,Object,Number],
	},
},
methods: {
	//clickButton是子组件的方法,不需要在父组件中@
	clickButton(){
		let v = 'qqqqqqqqqq';
		this.$emit('update:returnValue', v);
	}	
}

子组件参与uni-form的表单验证

将值传递给父页面中的uni-form-item

created() {			
		//初始化表单验证
		this.form = this.getForm('uniForms');
		this.formItem = this.getForm('uniFormsItem');
		if (this.form && this.formItem) {
			if (this.formItem.name) {
				this.formItem.setValue(this.data);//对应的值
				this.form.inputChildrens.push(this);
			}
		}
	},
},
method:{
	getForm(name = 'uniForms') {
		let parent = this.$parent;
		let parentName = parent.$options.name;
		while (parentName !== name) {
			parent = parent.$parent;
			if (!parent) return false;
			parentName = parent.$options.name;
		}
		return parent;
	}
}

A页面子组件uni.$emit发送参数,B页面子组件uni.$on接收不到

A页面的子组件通过$emit发送参数,页面跳转后由B页面的子组件接收通过uni.$on接收,如果此时B页面的子组件不使用computed来接收的话,很可能因为异步的原因,页面渲染完成才收到参数,无法正常获取。
很多人主动加上延时来实现参数收取,不仅仅丑陋,而且当真的遇到延迟,那可能又会出错,所以建议使用computed,这样才能实时

Vue3 中没有了 EventBus 跨组件通信,但是现在有了一个替代的方案 mitt.js,原理还是 EventBus

参考:
vue父组件给子组件的props传值的异步问题
Vue3.0 新特性以及使用经验总结
Vue3的8种和Vue2的12种组件通信,值得收藏


二、官方或第三方组件

uni-file-picker

问题

属性disablePreview=true,limit=1时,点击已上传图片,可再次选择图片,且图片可多选,最多9张图,之前已传图片保留不覆盖;
属性disablePreview=true,limit>1时,点击已上传图片,无法再次选图片;

解决

采用默认值,disablePreview=false,不使用该功能。


uni-list-item

问题

uni-list-item点击事件无效

解决

uni-list-item标签里添加link或者设clickable属性为true

<uni-list>
	<uni-list-item title="title" @click="openShow" link></uni-list-item>
	<uni-list-item title="title" @click="openShow" :clickable="true"></uni-list-item>
</uni-list>

uni-forms

问题

官方uni-forms组件的自定义验证规则在微信小程序中无效

解决

HBuilder版本到3.3.5.20211229后问题不存在

浏览器中运行正常,但微信小程序中失效,官网解释:自定义校验规则使用说明

注意 需要注意,如果需要使用 validateFunction 自定义校验规则,则不能采用 uni-forms 的 rules 属性来配置校验规则,这时候需要通过ref,在onReady生命周期调用组件的setRules方法绑定验证规则 无法通过props传递变量,是因为微信小程序会过滤掉对象中的方法,导致自定义验证规则无效。

实际上即便你加了这句也并没有什么卵用。

// HBuilder版本到3.3.5.20211229后不需要加
onReady() {
    this.$refs.form.setRules(this.rules)
},

翻来覆去找了半天,终于在官网论坛大神处找到解决办法:
#插件讨论# 【 Forms 表单 - DCloud前端团队 】rules 和 自定义校验组合使用不生效

以下为大佬手书:

自己手动修改:

  1. 表单规则是异步, 所以需要在组件初始化增加判断 如果初始化 需要变更规则
    文件位置:components->uni-forms->uni-forms.vue
    修改位置:methods -> init
// 原始代码
if (!this.validator) {
	this.validator = new Validator(formRules)
}

// 修改后代码
if (!this.validator) {
	this.validator = new Validator(formRules)
} else {
	this.validator.updateSchema(formRules)
}
  1. 修改Object.assign合并函数为ES6新方式合并
    文件位置: components->uni-forms->validate.js
    修改位置: Class RuleValidator->validateRule
// 原始代码:
Object.assign(rule, {
	label: fieldValue.label || `["${fieldKey}"]`
})

// 修改后代码:
rule = {...rule,...{
	label: fieldValue.label || `["${fieldKey}"]`
}}
  1. 另外
    由于实例给的表单填写为异步填写 会直接触发自定义验证
    个人在用例上直接改为了 异步填写为 默认显示 详细信息

经实测,仅修改第二部分154行就成功了,未测试第一部分影响。
第一部分最新官方代码就只有一句:this.validator = new Validator(formRules)
同时,那段没有什么卵用的还是要写的

展开运算符和object.assign()的区别
JavaScript中三个点代表什么
Object.assign()


在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值