父组件页面内设置自定组件,并且标记好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
onLoad
指的是页面加载,组件内只能使用 mounted
来代替实现。
onPullDownRefresh
、onReachBottom
很奇怪,目前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;
})
}
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>
具体情况及解决办法如下:
// 子组件
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是语法糖,默认情况下在vue2和vue3分别绑定input
和modelValue
的值。
//子组件的属性
// #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值》将使用本例中的语法糖
在子组件内可以直接调用参数 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-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;
}
}
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种组件通信,值得收藏
属性disablePreview=true,limit=1
时,点击已上传图片,可再次选择图片,且图片可多选,最多9张图,之前已传图片保留不覆盖;
属性disablePreview=true,limit>1
时,点击已上传图片,无法再次选图片;
采用默认值,disablePreview=false
,不使用该功能。
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组件的自定义验证规则在微信小程序中无效
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 和 自定义校验组合使用不生效
以下为大佬手书:
自己手动修改:
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)
}
components
->uni-forms
->validate.js
Class RuleValidator
->validateRule
// 原始代码:
Object.assign(rule, {
label: fieldValue.label || `["${fieldKey}"]`
})
// 修改后代码:
rule = {...rule,...{
label: fieldValue.label || `["${fieldKey}"]`
}}
经实测,仅修改第二部分154行就成功了,未测试第一部分影响。
第一部分最新官方代码就只有一句:this.validator = new Validator(formRules)
同时,那段没有什么卵用的还是要写的
展开运算符和object.assign()的区别
JavaScript中三个点代表什么
Object.assign()