• 微信小程序--下拉选择框组件封装,可CV直接使用


    一、起因

            接到的项目需求,查看ui设计图后,由于微信小程序官方设计的下拉选择框不符合需求,而且常用的第三方库也没有封装类似的,所以选择自己自定义组件。在此记录一下,方便日后复用。

            ui设计图如下:

            

            微信官方提供的选择框

            对比发现并不能实现我们想要的功能。

    二、自定义组件 

    2.1 封装品牌组件

    注:我这里的箭头是使用Vant-Weapp生成的,可自由替换组件或图片实现,把相应的wxss改掉即可

    代码如下

    • wxml
    1. <view class="select_all_view">
    2. <view class="select_title" wx:if="{{title}}">{{title}}view>
    3. <view class="select_view">
    4. <view class="inputPlaceholder" bindtap="startChange">
    5. <text class="text" wx:if='{{select}}' >{{select}}text>
    6. <text class="text" wx:else="{{select}}" >{{placeholder}}text>
    7. <view class="icon" wx:if='{{changable}}'>
    8. <van-icon name="arrow-down" />
    9. view>
    10. <view class="icon" wx:else='{{changable}}'>
    11. <van-icon name="arrow" />
    12. view>
    13. view>
    14. <view class="content" wx:if='{{changable}}'>
    15. <view class="{{item.id==selectId ? 'active':''}}" wx:for="{{selectcontent}}" wx:key="idnex" bindtap="changecontent" data-datavalue="{{item}}">
    16. {{item.name}}
    17. view>
    18. view>
    19. view>
    20. view>
    • wxss
    1. /* components/select-postSale.wxss */
    2. .select_all_view {
    3. display: flex;
    4. z-index: 999;
    5. }
    6. .select_view {
    7. display: inline;
    8. width: 200rpx;
    9. height: 64rpx;
    10. }
    11. /* .select_title {
    12. margin-right: 10rpx;
    13. } */
    14. .inputPlaceholder {
    15. min-width: 230rpx;
    16. height: 64rpx;
    17. background: #FFFFFF;
    18. border: 2rpx solid #D9D9D9;
    19. border-radius: 12rpx 12rpx 12rpx 12rpx;
    20. padding: 4rpx 0rpx 10rpx 10rpx;
    21. border-radius: 10rpx;
    22. position: relative;
    23. overflow: hidden;
    24. text-overflow: ellipsis;
    25. white-space: nowrap;
    26. font-size: 28rpx;
    27. font-family: PingFang SC-Regular, PingFang SC;
    28. font-weight: 400;
    29. color: #000000;
    30. line-height: 33rpx;
    31. }
    32. .select_view .inputPlaceholder .text {
    33. height: 40rpx;
    34. position: relative;
    35. top: 16rpx;
    36. left: 12rpx;
    37. }
    38. .icon {
    39. position: absolute;
    40. right: 12rpx;
    41. top: 20rpx;
    42. }
    43. .content {
    44. position: absolute;
    45. z-index: 999;
    46. width: 200rpx;
    47. max-height: 208rpx;
    48. background: #FFFFFF;
    49. box-shadow: 0rpx 12rpx 32rpx 0rpx rgba(0, 0, 0, 0.08), 0rpx 6rpx 12rpx -8rpx rgba(0, 0, 0, 0.12), 0rpx 18rpx 56rpx 16rpx rgba(0, 0, 0, 0.05);
    50. border-radius: 16rpx 16rpx 16rpx 16rpx;
    51. opacity: 1;
    52. margin-top: 8rpx;
    53. padding: 20rpx;
    54. overflow-x: hidden;
    55. overflow-y: scroll;
    56. display: flex;
    57. flex-direction: column;
    58. justify-content: center;
    59. align-items: center;
    60. }
    61. .select_view .content .active {
    62. width: 184rpx;
    63. height: 64rpx;
    64. background: #F9F9F9;
    65. border-radius: 0rpx 0rpx 0rpx 0rpx;
    66. opacity: 1;
    67. font-size: 28rpx;
    68. font-family: PingFang SC-Regular, PingFang SC;
    69. font-weight: 400;
    70. color: #000000;
    71. line-height: 33rpx;
    72. display: flex;
    73. justify-content: center;
    74. align-items: center;
    75. }
    76. .select_view .content .normal {
    77. width: 184rpx;
    78. height: 64rpx;
    79. background: #FFFFFF;
    80. border-radius: 0rpx 0rpx 0rpx 0rpx;
    81. opacity: 1;
    82. font-size: 28rpx;
    83. font-family: PingFang SC-Regular, PingFang SC;
    84. font-weight: 400;
    85. color: #000000;
    86. line-height: 33rpx;
    87. display: flex;
    88. justify-content: center;
    89. align-items: center;
    90. }
    • json
    1. {
    2. "component": true,
    3. "usingComponents": {
    4. "van-icon": "@vant/weapp/icon/index"
    5. }
    6. }
    •  js
    1. // components/select-postSale.js
    2. Component({
    3. properties: {
    4. title:{
    5. type: String,
    6. value: ""
    7. },
    8. nameList: {
    9. type: Array,
    10. value: [],
    11. observer: function(){
    12. //有的时候选项组是后端获取数据来的,初始化时可能为[],所以这里使用obersver,当父组件中值改变时触发
    13. this.processData();
    14. }
    15. },
    16. nowId: {
    17. type: Number,
    18. value: -1
    19. },
    20. nowName: {
    21. type: String,
    22. value: "",
    23. observer: function(){
    24. this.setData({select: this. properties.nowName,
    25. selectId: this.properties.nowId,});
    26. }
    27. },
    28. placeholder: {
    29. type: String,
    30. value: ""
    31. }
    32. },
    33. /**
    34. * 页面的初始数据
    35. */
    36. data: {
    37. selectcontent: [],
    38. changable: false, //箭头切换
    39. select: undefined, //选中的值
    40. selectId: undefined, //选中的id
    41. },
    42. methods: {
    43. // 下拉框收起和展开
    44. startChange(e) {
    45. this.setData({
    46. changable: !this.data.changable
    47. })
    48. },
    49. // 选择数据后回显
    50. changecontent(e) {
    51. this.setData({
    52. select: e.currentTarget.dataset.datavalue.name,
    53. selectId: e.currentTarget.dataset.datavalue.id,
    54. changable: false
    55. })
    56. this.triggerEvent("handleChange", {selectId: this.data.selectId, select: this.data.select});//向父组件传参
    57. },
    58. //处理数据,复制一遍,因为子组件不能直接改变父组件的传进来的值。
    59. processData(){
    60. let options = [];
    61. let that = this;
    62. this.properties.nameList.forEach((item) => {
    63. options.push({
    64. id: item.id,
    65. name: item.name,
    66. });
    67. }); //forEach
    68. this.setData({
    69. selectcontent: options,
    70. select: that.properties.nowName,
    71. selectId: that.properties.nowId,
    72. });
    73. }
    74. }
    75. })

    2.2 组件调用与ui原型图对比

            在要使用组件的页面js中添加自己想要的数据

    • js
    1. data: {
    2. curfId: 1,
    3. brandList: [{name: "万达影视" ,id: 1},
    4. {name: "金逸影视" ,id: 2},
    5. {name: "CGV" ,id: 3}
    6. ],
    7. curBrandName:"万达影视" ,
    8. }
    • wxml 
    <select-postSale nowId="{{curfId}}" nameList="{{brandList}}" nowName="{{curBrandName}}" placeholder="请选择品牌" bind:handleChange="changeBrand">select-postSale>
    • json
    1. "usingComponents": {
    2. "van-icon": "@vant/weapp/icon/index",
    3. "select-postSale":"/components/select-postSale/select-postSale"
    4. },
    5. "navigationStyle": "custom"

        ui设计图与效果对比

            可以看到效果已经基本实现.具体细节需要优化一下

    2.3 封装下方灰色区域组件

            这个组件有两个地方使用,样式基本相同,拿上方的品牌组件修改一下样式即可

    代码如下

    • wxml
    1. "select_all_view">
    2. "select_view">
    3. "inputPlaceholder" bindtap="startChange">
    4. "text" wx:if='{{select}}' >{{select}}
    5. "text" wx:else="{{select}}" >{{placeholder}}
    6. "icon" wx:if='{{changable}}'>
    7. "arrow-down" />
    8. "icon" wx:else='{{changable}}'>
    9. "arrow" />
    10. "content" wx:if='{{changable}}'>
    11. "{{item.id==selectId ? 'active':'normal'}}" wx:for="{{selectcontent}}" wx:key="idnex" bindtap="changecontent" data-datavalue="{{item}}">
    12. {{item.name}}
    • wxss
    1. /* components/select-postSale.wxss */
    2. .select_all_view {
    3. display: flex;
    4. z-index: 999;
    5. width: 654rpx;
    6. height: 104rpx;
    7. background: #F9F9F9;
    8. border-radius: 12rpx 12rpx 12rpx 12rpx;
    9. opacity: 1;
    10. }
    11. .select_view {
    12. display: inline;
    13. /* width: 200rpx;
    14. height: 64rpx; */
    15. }
    16. .inputPlaceholder {
    17. min-width: 654rpx;
    18. height: 82rpx;
    19. background: #F9F9F9;
    20. border: 2rpx solid #D9D9D9;
    21. border-radius: 12rpx 12rpx 12rpx 12rpx;
    22. padding: 4rpx 0rpx 10rpx 10rpx;
    23. /* color: #252525;
    24. font-weight: 400; */
    25. border-radius: 10rpx;
    26. position: relative;
    27. overflow: hidden;
    28. text-overflow: ellipsis;
    29. white-space: nowrap;
    30. font-size: 32rpx;
    31. font-family: PingFang SC-Regular, PingFang SC;
    32. font-weight: 600;
    33. color: #000000;
    34. line-height: 38rpx;
    35. }
    36. .select_view .inputPlaceholder .text {
    37. height: 40rpx;
    38. position: relative;
    39. top: 30rpx;
    40. left: 24rpx;
    41. }
    42. .icon {
    43. position: absolute;
    44. right: 24rpx;
    45. top: 30rpx;
    46. }
    47. .content {
    48. position: absolute;
    49. z-index: 999;
    50. min-width: 626rpx;
    51. max-height: 516rpx;
    52. background: #FFFFFF;
    53. box-shadow: 0rpx 12rpx 32rpx 0rpx rgba(0, 0, 0, 0.08), 0rpx 6rpx 12rpx -8rpx rgba(0, 0, 0, 0.12), 0rpx 18rpx 56rpx 16rpx rgba(0, 0, 0, 0.05);
    54. border-radius: 16rpx 16rpx 16rpx 16rpx;
    55. opacity: 1;
    56. margin-top: 8rpx;
    57. padding: 20rpx;
    58. overflow-x: hidden;
    59. overflow-y: scroll;
    60. display: flex;
    61. flex-direction: column;
    62. justify-content: center;
    63. align-items: center;
    64. }
    65. .content>.inputPlaceholder {
    66. padding: 10rpx 0;
    67. }
    68. .select_view .active {
    69. width: 638rpx;
    70. height: 100rpx;
    71. background: #F9F9F9;
    72. font-size: 32rpx;
    73. font-family: PingFang SC-Regular, PingFang SC;
    74. font-weight: 600;
    75. color: #000000;
    76. line-height: 38rpx;
    77. display: flex;
    78. justify-content: center;
    79. align-items: center;
    80. }
    81. .select_view .normal {
    82. width: 638rpx;
    83. height: 100rpx;
    84. border-radius: 16rpx 16rpx 16rpx 16rpx;
    85. opacity: 1;
    86. font-size: 32rpx;
    87. font-family: PingFang SC-Regular, PingFang SC;
    88. font-weight: 600;
    89. color: #000000;
    90. line-height: 38rpx;
    91. display: flex;
    92. justify-content: center;
    93. align-items: center;
    94. }
    • json
    1. {
    2. "component": true,
    3. "usingComponents": {
    4. "van-icon": "@vant/weapp/icon/index"
    5. }
    6. }
    • js
      1. // components/select-postSale.js
      2. Component({
      3. properties: {
      4. title:{
      5. type: String,
      6. value: ""
      7. },
      8. nameList: {
      9. type: Array,
      10. value: [],
      11. observer: function(){
      12. //有的时候选项组是后端获取数据来的,初始化时可能为[],所以这里使用obersver,当父组件中值改变时触发
      13. this.processData();
      14. }
      15. },
      16. nowId: {
      17. type: Number,
      18. value: -1
      19. },
      20. nowName: {
      21. type: String,
      22. value: "",
      23. observer: function(){
      24. this.setData({select: this. properties.nowName,
      25. selectId: this.properties.nowId,});
      26. }
      27. },
      28. placeholder: {
      29. type: String,
      30. value: ""
      31. }
      32. },
      33. /**
      34. * 页面的初始数据
      35. */
      36. data: {
      37. selectcontent: [],
      38. changable: false, //箭头切换
      39. select: undefined, //选中的值
      40. selectId: undefined, //选中的id
      41. },
      42. methods: {
      43. // 下拉框收起和展开
      44. startChange(e) {
      45. this.setData({
      46. changable: !this.data.changable
      47. })
      48. },
      49. // 选择数据后回显
      50. changecontent(e) {
      51. this.setData({
      52. select: e.currentTarget.dataset.datavalue.name,
      53. selectId: e.currentTarget.dataset.datavalue.id,
      54. changable: false
      55. })
      56. this.triggerEvent("handleChange", {selectId: this.data.selectId, select: this.data.select});//向父组件传参
      57. },
      58. //处理数据,复制一遍,因为子组件不能直接改变父组件的传进来的值。
      59. processData(){
      60. let options = [];
      61. let that = this;
      62. this.properties.nameList.forEach((item) => {
      63. options.push({
      64. id: item.id,
      65. name: item.name,
      66. });
      67. }); //forEach
      68. this.setData({
      69. selectcontent: options,
      70. select: that.properties.nowName,
      71. selectId: that.properties.nowId,
      72. });
      73. }
      74. }
      75. })

    2.4 第二个组件调用与ui原型图对比 

            跟上方调用组件一样.在使用组件页面js中添加数据,这里调用两次组件即可,只是展示数据不一样

    • js
    1. /**
    2. * 页面的初始数据
    3. */
    4. data: {
    5. curfId: 1,
    6. filmList: [{name: "坚如磐石" ,id: 1},
    7. {name: "变形金刚3" ,id: 2},
    8. {name: "复仇者联盟5" ,id: 3}
    9. ],
    10. curFilmName: "复仇者联盟5",
    11. dateList: [{name: "2023/10/16" ,id: 1},
    12. {name: "2023/10/23" ,id: 2},
    13. {name: "2023/10/30" ,id: 3}
    14. ],
    15. curDateName: "2023/10/16",
    16. },
    • wxml
    1. "{{curfId}}" nameList="{{filmList}}" nowName="{{curFilmName}}" placeholder="请选择要更换的电影">
    2. "{{curfId}}" nameList="{{dateList}}" nowName="{{curDateName}}" placeholder="请选择要修改的日期">
    • json 
    1. "usingComponents": {
    2. "van-icon": "@vant/weapp/icon/index",
    3. "select-postSale_2":"/components/select-postSale_2/select-postSale_2"
    4. },
    5. "navigationStyle": "custom"

            ui原型图与实现效果对比

    电影部分

    日期部分

    三、自定义修改说明 


    • 选择框的大小修改inputPlaceholder样式即可

    举个栗子: 此处我修改了宽度与背景色

    .inputPlaceholder {
      min-width: 400rpx;//修改后的宽度
      height: 82rpx;
      background: #FF00FF; // 修改后的背景色
      border: 2rpx solid #D9D9D9;
      border-radius: 12rpx 12rpx 12rpx 12rpx;
      padding: 4rpx 0rpx 10rpx 10rpx;
      position: relative;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      font-size: 32rpx;
      font-family: PingFang SC-Regular, PingFang SC;
      font-weight: 400;
      color: #000000;
      line-height: 38rpx;
    }

    • 选择后的弹窗修改content样式即可 
    • 选中样式修改active,没选中样式修改normal,弹窗大小修改content

    举个栗子:此处修改选中的背景色与没选中的背景色(懒人,修改背景色容易区分)

    • active

    .select_view .active {

      width: 638rpx;

      height: 100rpx;

      background: #32CD32;  // 修改后背景色

      font-size: 32rpx;

      font-family: PingFang SC-Regular, PingFang SC;

      font-weight: 400;

      color: #000000;

      line-height: 38rpx;

      display: flex;

      justify-content: center;

      align-items: center;

    }

    • normal

    .select_view .normal {

      width: 638rpx;

      height: 100rpx;

      background: #FF6347;  // 修改后背景色

      opacity: 1;

      font-size: 32rpx;

      font-family: PingFang SC-Regular, PingFang SC;

      font-weight: 400;

      color: #000000;

      line-height: 38rpx;

      display: flex;

      justify-content: center;

      align-items: center;

    }

    其他的需要自定义的依照自己ui样式修改即可。 

     

  • 相关阅读:
    uname
    transformer模型训练结构解析(加深理解)
    hadoop MapReduce运营商案例关于用户基站停留数据统计
    RC-u4 相对论大师(bfs求解指定路径)
    springboot结合elasticJob
    Linux open suse15==安装pcre zlib openssl nginx 关防火墙 安装httpd
    项目管理中最常见的问题有哪些?
    对Python3.8配置OpenCV4.5.5中
    Java学习 --- 面向对象之继承
    Python如何将项目直接打包为一键整合包
  • 原文地址:https://blog.csdn.net/m0_74444744/article/details/133787501