十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

uni-app x 中 picker-view 滚动选择器组件详解:属性、事件与跨端实战

uni-app x 中 picker-view 滚动选择器组件详解:属性、事件与跨端实战 uni-app x 中 picker-view 滚动选择器组件详解属性、事件与跨端实战【免费下载链接】uni-appA cross-platform framework using Vue.js项目地址: https://gitcode.com/gh_mirrors/un/uni-app组件类型UniPickerViewElementpicker-view是 uni-app x 中用于嵌入页面内部的滚动选择器组件与之相对的是弹出式的picker组件。它常与滚动列子组件picker-view-column配合实现年月日、时分秒、地址等多列联动选择也可作为form表单的受控控件随表单一起提交。本文将从组件定位、全部属性与事件、跨端兼容性、源码级示例、表单集成以及自动化测试验证等角度带你完整掌握在 uni-app x 中开发滚动选择器的能力。组件定位嵌入页面 vs 弹出式选择器在 uni-app x 组件体系中选择类交互通常有两种实现picker弹出式点击触发系统级或自定义弹层用户选择后关闭适合不常驻页面的单选、多列联动、时间、日期等场景。picker-view嵌入式直接渲染在页面中用户可随时滚动各列并实时看到选中结果适合需要常驻展示、多列联动的场景如日期面板、自定义时间选择器。picker-view的组件类型为UniPickerViewElement其内部每一列都是一个picker-view-column子组件。需要特别强调的是picker-view-column仅可放置于picker-view /内部且其子节点不会自动继承选中框的高度需要自行设置高度并居中。兼容性概览picker-view及picker-view-column在各大端均有支持当前仓库文档记录的最小兼容版本如下| 平台 | Web | 微信小程序 | Android | iOS | HarmonyOS | | :- | :- | :- | :- | :- | :- | | picker-view | 4.0 | 4.41 | 3.9 | 4.11 | 4.61 | | picker-view-column | 4.0 | 4.41 | 3.9 | 4.11 | 4.61 |上表对应 HBuilderX 的版本号。个别属性如indicator-class、mask-style在 Android/iOS 上标记为不支持x具体见下文属性表。属性详解picker-view的全部属性如下表所示其中name与value用于与form组件联动其余均为视觉层配置| 名称 | 类型 | 兼容性 | 描述 | | :- | :- | :-: | :- | | name | string | Web: 4.0; 微信小程序: 4.41; Android: 3.9; iOS: 4.11; HarmonyOS: 4.61 | 表单的控件名称作为键值对的一部分与表单(form组件)一同提交 | | value | number[] | Web: 4.0; 微信小程序: 4.41; Android: 3.9; iOS: 4.11; HarmonyOS: 4.61 | 表单的控件值作为键值对的一部分与表单(form组件)一同提交 | | indicator-style | string(string.CSSString) | Web: 4.0; 微信小程序: 4.41; Android: 3.9; iOS: 4.11; HarmonyOS: 4.61 | 指示器样式 | | indicator-class | string(string.ClassString) | Web: 4.0; 微信小程序: 4.41; Android: x; iOS: x; HarmonyOS: 4.61 | 设置选择器中间选中框的类名 | | mask-style | string(string.CSSString) | Web: 4.0; 微信小程序: 4.41; Android: x; iOS: x; HarmonyOS: 4.61 | 设置蒙层的样式 | | mask-top-style | string(string.CSSString) | Web: x; 微信小程序: x; Android: 3.9; iOS: 4.11; HarmonyOS: 4.61 | 遮罩顶部类 | | mask-bottom-style | string(string.CSSString) | Web: x; 微信小程序: x; Android: 3.9; iOS: 4.11; HarmonyOS: 4.61 | 遮罩底部类 | | mask-class | string(string.ClassString) | Web: 4.0; 微信小程序: 4.41; Android(VDOM): x; Android(Vapor): 5.21; iOS(VDOM): x; iOS(Vapor): 5.11; HarmonyOS: 4.61 | 遮罩类 |各属性要点name / value用于表单提交。在仓库的 form 表单示例 中picker-view被直接放在form内并指定nametime、:valuedata.time配合两列picker-view-column实现时分选择表单提交后formData[time]即为当前选中的下标数组。该组件的表单行为目前主要在微信小程序与鸿蒙端验证通过见 form 测试。indicator-style / indicator-class设置中间选中框指示器的样式。示例中通过indicatorStyle: height: 50px;定义选中框高度选中项文本通过line-height: 50px; text-align: center;实现居中。mask-style / mask-class设置选中框上下的**蒙层遮罩渐变**样式通常用于营造当前项高亮、其余项渐变淡化的视觉层次。mask-top-style / mask-bottom-style仅 App 端Android/iOS与 HarmonyOS 支持的上下遮罩独立样式可分别对选中框上方与下方设置不同的渐变背景。类型说明indicator-style、mask-style、mask-top-style、mask-bottom-style的类型是string.CSSStringCSS 属性和属性值的组合字符串indicator-class、mask-class的类型是string.ClassString元素全局属性class的值。这两类特殊值域 string 属于开发时类型可在 HBuilderX 中获得代码提示与语法校验运行时会被统一抹平为普通string详见 UTS 特殊值域 string。属性支持的平台差异矩阵从兼容性列可以归纳出明显的平台分工Web / 微信小程序 / HarmonyOS完整支持indicator-class、mask-style、mask-classAndroid / iOSVDOM 渲染不支持上述三类而是通过mask-top-style/mask-bottom-style提供上下蒙层定制Android / iOSVapor 新渲染引擎从 5.21 / 5.11 起开始支持mask-class见属性表中的Android(Vapor): 5.21、iOS(Vapor): 5.11。开发时如需针对不同端差异化设置样式可使用条件编译指令#ifdef/#ifndef分别编写各端分支仓库示例即采用了这一模式。事件详解change当滚动选择、value改变时触发。事件对象类型为UniPickerViewChangeEvent其detail为UniPickerViewChangeEventDetail。UniPickerViewChangeEventDetail 的属性值| 名称 | 类型 | 必填 | | :- | :- | :- | | value | Arraynumber | 是 |event.detail {value: value}value为数组表示picker-view内各picker-view-column当前选中的是第几项下标从 0 开始数组长度与列数一致。从事件类型结构看UniPickerViewChangeEvent继承自泛型事件UniCustomEventUniPickerViewChangeEventDetail因此除了detail.value外还具备通用自定义事件的type、target、currentTarget等标准字段uni-app x 通用事件约定见 组件通用事件文档。在 日期选择器示例 的bindChange回调中可通过e.detail.value拿到三列下标再映射回数据数组得到具体的年、月、日const bindChange (e : UniPickerViewChangeEvent) { const val e.detail.value data.result val data.year data.years[val[0]] data.month data.months[val[1]] data.day data.days[val[2]] }pickstart / pickend| 名称 | 类型 | 兼容性 | 描述 | | :- | :- | :-: | :- | | pickstart | eventhandle | Web: x; 微信小程序: 4.41; Android: x; iOS: x; HarmonyOS: x | 当滚动选择开始时候触发事件 | | pickend | eventhandle | Web: x; 微信小程序: 4.41; Android: x; iOS: x; HarmonyOS: x | 当滚动选择结束时候触发事件 |目前这两个事件仅微信小程序端支持可用于监听用户开始滚动与滚动结束的时刻例如在滚动期间暂停某些高频计算、结束后统一提交结果。子组件 picker-view-columnpicker-view-column仅可放置于picker-view中用于定义一列可滚动的选项。其子节点未继承picker-view的选中框高度需要自己设置高度并居中。属性| 名称 | 类型 | 兼容性 | | :- | :- | :-: | | value | number | HarmonyOS(Vapor): 5.0 |value属性当前在 HarmonyOS Vapor 渲染引擎5.0下支持用于指定该列的初始选中下标。使用方式每一列通过v-for渲染选项即可选项的高度即一格的滚动步长例如picker-view-column classpicker-view-column view classitem v-for(item,index) in data.months :keyindex text classtext{{item}}月/text /view /picker-view-column配套样式需自行保证每个选项高度与指示器高度一致示例中为 50px并让文本垂直居中.item { height: 50px; } .text { line-height: 50px; text-align: center; }完整示例日期选择器年月日三列联动以下为官方示例与仓库中 hello uni-app x 日期选择器页 同源的完整实现它演示了picker-view的全部属性用法value 双向联动、change 事件映射、指示器与蒙层样式/类名的动态切换以及针对不同端Web/微信、App、鸿蒙的条件编译。template view page-head :titledata.title/page-head view classuni-padding-wrap view classuni-title 日期{{data.year}}年{{data.month}}月{{data.day}}日 /view /view picker-view classpicker-view :valuedata.value changebindChange :indicator-styledata.indicatorStyle :indicator-classdata.indicatorClass :mask-styledata.maskStyle :mask-classdata.maskClass :mask-top-styledata.maskTopStyle :mask-bottom-styledata.maskBottomStyle picker-view-column classpicker-view-column view classitem v-for(item,index) in data.years :keyindextext classtext{{item}}年/text/view /picker-view-column picker-view-column classpicker-view-column view classitem v-for(item,index) in data.months :keyindextext classtext{{item}}月/text /view /picker-view-column picker-view-column classpicker-view-column view classitem v-for(item,index) in data.days :keyindextext classtext{{item}}日/text/view /picker-view-column /picker-view !-- #ifndef MP-ALIPAY -- boolean-data :defaultValuefalse title设置选择器中间选中框的样式 changesetIndicatorStyle/boolean-data !-- #endif -- !-- #ifdef WEB || MP-WEIXIN -- boolean-data :defaultValuefalse title设置选择器中间选中框的类名 changesetIndicatorClass/boolean-data boolean-data :defaultValuefalse title设置蒙层的样式 changesetMaskStyle/boolean-data boolean-data :defaultValuefalse title设置蒙层的类名 changesetMaskClass/boolean-data !-- #endif -- !-- #ifdef APP -- boolean-data :defaultValuefalse title设置蒙层上半部分的样式 changesetMaskTopStyle/boolean-data boolean-data :defaultValuefalse title设置蒙层下半部分的样式 changesetMaskBottomStyle/boolean-data !-- #endif -- /view /template script setup languts import { state, setEventCallbackNum } from /store/index.uts type DataType { title: string; years: number[]; year: number; months: number[]; month: number; days: number[]; day: number; value: number[]; result: number[]; indicatorStyle: string; indicatorClass: string; maskStyle: string; maskClass: string; maskTopStyle: string; maskBottomStyle: string; } // 初始化数据 const _years : number[] [] const _year 2018 const _months : number[] [] const _month : number 1 const _days : number[] [] const _day 12 for (let i 2000; i _year; i) { _years.push(i) } for (let i 1; i 12; i) { _months.push(i) } for (let i 1; i 31; i) { _days.push(i) } // 使用reactive避免ref数据在自动化测试中无法访问 const data reactive({ title: picker-view, years: _years, year: _year, months: _months, month: _month, days: _days, day: _day, value: [_year - 2000, _month - 1, _day - 1], result: [], indicatorStyle: height: 50px;, indicatorClass: , maskStyle: , maskClass: , maskTopStyle: , maskBottomStyle: } as DataType) const setIndicatorStyle (checked : boolean) { const extraStyle height: 50px;border:#ff5500 solid 1px;background:rgba(182, 179, 255, 0.4);; // #ifdef APP-HARMONY data.indicatorStyle checked ? extraStyle : height: 50px;border:none;background:transparent;; // #endif // #ifndef APP-HARMONY data.indicatorStyle checked ? extraStyle : height: 50px;; // #endif } const setIndicatorClass (checked : boolean) { data.indicatorClass checked ? indicator-test : } const setMaskStyle (checked : boolean) { const extraMaskStyle background-image: linear-gradient(to bottom, #d8e5ff, rgba(216, 229, 255, 0)); data.maskStyle checked ? extraMaskStyle : } const setMaskClass (checked : boolean) { data.maskClass checked ? mask-test : } const setMaskTopStyle (checked : boolean) { const linearToTop background-image: linear-gradient(to bottom, #f4ff73, rgba(216, 229, 255, 0)); // #ifdef APP-HARMONY !VUE3-VAPOR data.maskTopStyle checked ? linearToTop : background-image: linear-gradient(to bottom, transparent, transparent); // #endif // #ifdef APP-HARMONY VUE3-VAPOR data.maskTopStyle checked ? linearToTop : // #endif // #ifndef APP-HARMONY data.maskTopStyle checked ? linearToTop : // #endif } const setMaskBottomStyle (checked : boolean) { const linearToBottom background-image: linear-gradient(to top, #f4ff73, rgba(216, 229, 255, 0)); // #ifdef APP-HARMONY !VUE3-VAPOR data.maskBottomStyle checked ? linearToBottom : background-image: linear-gradient(to bottom, transparent, transparent); // #endif // #ifdef APP-HARMONY VUE3-VAPOR data.maskBottomStyle checked ? linearToBottom : // #endif // #ifndef APP-HARMONY data.maskBottomStyle checked ? linearToBottom : // #endif } const bindChange (e : UniPickerViewChangeEvent) { const val e.detail.value data.result val data.year data.years[val[0]] data.month data.months[val[1]] data.day data.days[val[2]] } const setValue () { data.value [0, 1, 30] as number[] } const setValue1 () { data.value [10, 10, 10] as number[] } defineExpose({ data, setIndicatorStyle, setIndicatorClass, setMaskStyle, setMaskClass, setMaskTopStyle, setMaskBottomStyle, setValue, setValue1 }) /script style .picker-view { width: 100%; height: 320px; margin-top: 10px; margin-bottom: 20px; } .item { height: 50px; } .text { line-height: 50px; text-align: center; } .indicator-test { height: 50px; border: #ff5500 solid 1px; background:rgba(182, 179, 255, 0.4); } .mask-test { background-image: linear-gradient(to bottom, #d8e5ff, rgba(216, 229, 255, 0)); } /style示例要点解读数据初始化与 value 映射三列数据分别由_years、_months、_days数组生成data.value初始为[_year - 2000, _month - 1, _day - 1]即2018 年 1 月 12 日对应的三列下标说明value数组存放的是下标而非值。change 回调bindChange从e.detail.value取到三列下标后用data.years[val[0]]等映射回真实年月日并驱动视图更新。动态样式开关setIndicatorStyle、setMaskStyle等方法通过切换布尔开关演示了指示器/蒙层的样式与类名动态设置。其中鸿蒙端在关闭indicatorStyle时会显式复位border:none;background:transparent;而其他端只需恢复height: 50px;体现了跨端细节差异。条件编译Web/微信端使用indicator-class、mask-style、mask-classApp 端使用mask-top-style、mask-bottom-style支付宝小程序不参与指示器样式开关演示见下文注意事项。defineExpose将data及各类方法暴露给外部供页面控制或自动化测试调用。组件复用与外部控制在实际项目中picker-view常被封装为独立组件复用。仓库提供了 wrap-picker-view.uvue 这一包装示例演示了通过ref$callMethod调用子组件方法script setup languts import MyPickerView from ./picker-view.uvue const visible ref(false) const pickerViewRef refComponentPublicInstance | null(null) function setValue() { if (pickerViewRef.value ! null) { pickerViewRef.value!.$callMethod(setValue) } } function toggle() { visible.value !visible.value if (visible.value) { nextTick(() { setValue() }) } } /script该示例还演示了配合v-if的懒挂载场景组件首次渲染后在nextTick中调用其暴露的setValue方法将三列滚动到指定位置说明picker-view的value不仅支持声明式绑定也支持通过暴露方法在特定时机强制设置。与 form 表单集成picker-view可以通过name与value作为表单控件提交。仓库 form 表单示例 中有一段时间选择控件picker-view classpicker-view nametime :valuedata.time indicator-styleheight:50px picker-view-column view classpicker-view-item v-for(item,index) in data.hours :keyindex text classpicker-view-text{{item}}时/text /view /picker-view-column picker-view-column view classpicker-view-item v-for(item,index) in data.minutes :keyindex text classpicker-view-text{{item}}分/text /view /picker-view-column /picker-view配合form的submit提交数据中会出现以name为键、当前选中下标数组为值的条目。仓库 form 自动化测试 验证了该场景// 仅微信 和 鸿蒙支持 picker-view 表单 expect(formData[time][0]).toBe(time[0]) expect(formData[time][1]).toBe(time[1])测试注释明确指出picker-view 作为表单控件的提交能力目前主要在微信小程序与鸿蒙端验证通过跨端使用时需注意各平台对表单集成的支持程度。平台差异与注意事项支付宝小程序动态设置指示器样式可能偏移支付宝小程序动态设置picker-view指示器样式时可能出现偏移建议使用静态配置避免运行时修改指示器样式。这也是官方示例中setIndicatorStyle的演示开关使用!-- #ifndef MP-ALIPAY --排除支付宝小程序的原因。蒙层/指示器各端支持情况蒙层mask-style、mask-class与指示器类名indicator-class在Web、微信小程序、HarmonyOS上支持Android/iOS 的 VDOM 渲染不支持但Vapor 新渲染引擎从 5.21Android/ 5.11iOS起开始支持mask-class上下蒙层mask-top-style、mask-bottom-style为App 端Android/iOS与 HarmonyOS特有属性Web 与小程序不支持pickstart、pickend目前仅微信小程序支持。内容较长时的滚动容器选择若picker-view所在页面内容较长、需要整体滚动应使用list-view而不是scroll-view作为外层容器见仓库tips说明以保证长内容场景下的滚动性能与体验。自动化测试行为验证与截图基线仓库为picker-view编写了完整的自动化测试 picker-view.test.js覆盖了以下行为可作为理解组件行为的佐证value 编程式设置调用setValue将value置为[0, 1, 30]后断言picker-view的value属性为0,1,30仅在 App 端Android/iOSsetValue会触发 change 事件此时可进一步断言data.result同步为[0, 1, 30]。列数量校验页面中picker-view数量为 1、picker-view-column数量为 3。指示器/蒙层属性校验在 Web/小程序端分别断言indicator-class、mask-style、mask-class的设置值如indicator-test、渐变色mask-style在 App 端断言mask-top-style、mask-bottom-style的设置与清空。事件回调计数设置 value 使年月日三列各滚动一次统计change触发的e.target?.tagName含PICKER-VIEW与e.type change的累计次数断言结果为 9验证了事件的触发链路与字段结构。重进页面状态还原切换 Tab 后重新进入页面断言初始数据仍为 2018 年 1 月 12 日验证组件状态可正确初始化。上述测试同时使用toSaveImageSnapshot保存各状态的截图基线如picker-view-indicator-style、picker-view-app-mask-top-bottom-style用于各端视觉回归比对。常见用法小结多列联动选择在picker-view内放置多个picker-view-column通过change的detail.value下标数组映射出各列选中值适合日期、时间、地区联动。与表单配合指定name与value将选中下标随form一并提交注意平台支持差异。视觉定制优先用indicator-style/indicator-class定制选中框用mask-style/mask-top-style/mask-bottom-style定制上下渐变蒙层不同端按属性兼容矩阵使用条件编译区分。长内容场景页面滚动容器使用list-viewpicker-view-column内的每个选项自行设置高度并居中。类似场景的更高阶封装若需要弹出式、分列加载的多列选择如地址选择可考虑使用 uni-ui 中基于 DataCom 规范封装的uni-data-picker组件它与本文的嵌入式picker-view使用场景互补。参考组件文档picker-view、picker-view-column完整示例日期选择器页源码、组件复用包装示例自动化测试picker-view.test.js表单集成示例form.uvue 与 form.test.js相关类型说明UTS 特殊值域 stringstring.CSSString / string.ClassString【免费下载链接】uni-appA cross-platform framework using Vue.js项目地址: https://gitcode.com/gh_mirrors/un/uni-app创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表