• 微信小程序 实现滑块是矩形的slider组件


    我发现大多数前端UI库都是圆形的滑块,而且圆形的滑块都没有紧贴进度条,都是超出了首尾端,所以亲自写一个矩形的滑块,我使用了微信小程序的wxs的事件通信写法,官方说这样写好,也不知道好哪里了。样式如下图:

    js

    1. // components/slider/index.js
    2. Component({
    3. // 启用插槽
    4. options: {
    5. multipleSlots: true
    6. },
    7. /**
    8. * 组件的属性列表
    9. */
    10. properties: {
    11. disabled: {
    12. type: Boolean,
    13. value: false,
    14. observer(val, oldVal) {
    15. if (val !== this.value) {
    16. this.setData({
    17. ['propValue.disabled']: val
    18. })
    19. }
    20. },
    21. },
    22. max: {
    23. type: Number,
    24. value: 100,
    25. observer(val, oldVal) {
    26. if (val !== this.value) {
    27. this.setData({
    28. ['propValue.max']: val
    29. })
    30. }
    31. },
    32. },
    33. min: {
    34. type: Number,
    35. value: 0,
    36. observer(val, oldVal) {
    37. if (val !== this.value) {
    38. this.setData({
    39. ['propValue.min']: val
    40. })
    41. }
    42. },
    43. },
    44. step: {
    45. type: Number,
    46. value: 1,
    47. observer(val, oldVal) {
    48. if (val !== this.value) {
    49. this.setData({
    50. ['propValue.step']: val
    51. })
    52. }
    53. },
    54. },
    55. value: {
    56. type: null,
    57. value: 0,
    58. observer(val, oldVal) {
    59. if (val !== this.value) {
    60. this.setData({
    61. ['propValue.value']: val
    62. })
    63. }
    64. },
    65. }
    66. },
    67. /**
    68. * 组件的初始数据
    69. */
    70. data: {
    71. propValue: {
    72. disabled: null,
    73. max: null,
    74. min: null,
    75. step: null,
    76. value: null
    77. }
    78. },
    79. lifetimes: {
    80. attached() {
    81. this.data.propValue.disabled = this.data.disabled;
    82. this.data.propValue.max = this.data.max;
    83. this.data.propValue.min = this.data.min;
    84. this.data.propValue.step = this.data.step;
    85. this.data.propValue.value = this.data.value;
    86. this.setData({
    87. propValue: this.data.propValue
    88. })
    89. }
    90. },
    91. /**
    92. * 组件的方法列表
    93. */
    94. methods: {
    95. setVal(val) {
    96. // this.setData({
    97. // value: val
    98. // })
    99. }
    100. }
    101. })

    wxml

    1. <wxs module="computed" src="./index.wxs">wxs>
    2. <view class="n-slider {{disabled?'n-slider__disabled':''}}" change:prop="{{computed.propObserver}}" prop="{{propValue}}" bind:tap="{{computed.onClick}}" bind:touchstart="{{computed.onTouchStart}}" catch:touchmove="{{computed.onTouchMove}}" bind:touchend="{{computed.onTouchEnd}}" bind:touchcancel="{{computed.onTouchEnd}}">
    3. <view class="n-slider-rail">
    4. <view class="n-slider-rail__fill">view>
    5. <view class="n-slider-handles">
    6. <view class="n-slider-handle-wrapper">
    7. <view class="n-slider-handle">
    8. <slot>slot>
    9. view>
    10. view>
    11. view>
    12. view>
    13. view>

    wxs 

    1. var DRAG_STATUS = {
    2. START: 'start',
    3. MOVING: 'moving',
    4. END: 'end',
    5. };
    6. var dragStatus = DRAG_STATUS.START;
    7. var propValue = {
    8. disabled: false,
    9. max: 100,
    10. min: 0,
    11. step: 1,
    12. value: 0
    13. }
    14. var newValue;
    15. function onTouchStart(event, ins) {
    16. var disabled = propValue.disabled;
    17. if (disabled) {
    18. return;
    19. }
    20. newValue = propValue.value;
    21. dragStatus = DRAG_STATUS.START;
    22. }
    23. function onTouchMove(event, ins) {
    24. var disabled = propValue.disabled;
    25. if (disabled) {
    26. return;
    27. }
    28. if (dragStatus === DRAG_STATUS.START) {
    29. ins.triggerEvent('drag-start');
    30. }
    31. dragStatus = DRAG_STATUS.MOVING;
    32. var touch = event.touches[0];
    33. var rect = ins.selectComponent('.n-slider-handles').getBoundingClientRect();
    34. var percentage = (touch.clientX - rect.left) / rect.width;
    35. newValue = percentageToValue(percentage);
    36. updateValue(ins, newValue, false, true);
    37. }
    38. function onTouchEnd(event, ins) {
    39. var disabled = propValue.disabled;
    40. if (disabled) {
    41. return;
    42. }
    43. if (dragStatus === DRAG_STATUS.MOVING) {
    44. dragStatus = DRAG_STATUS.END;
    45. updateValue(ins, newValue, true);
    46. ins.triggerEvent('drag-end');
    47. }
    48. }
    49. function onClick(event, ins) {
    50. var disabled = propValue.disabled;
    51. if (disabled) {
    52. return;
    53. }
    54. var touch = event.touches[0];
    55. var rect = ins.selectComponent('.n-slider-handles').getBoundingClientRect();
    56. var percentage = (touch.clientX - rect.left) / rect.width;
    57. updateValue(ins, percentageToValue(percentage), true);
    58. }
    59. /**
    60. * 限制拖动值不能超出最小和最大范围
    61. * @param value
    62. */
    63. function format(value) {
    64. return Math.round(Math.max(propValue.min, Math.min(value, propValue.max)) / propValue.step) * propValue.step;
    65. }
    66. /**
    67. *
    68. * @param ins
    69. * @param val 不能和value重复
    70. * @param end
    71. * @param drag
    72. */
    73. function updateValue(ins, val, end, drag) {
    74. value = format(val);
    75. ins.selectComponent('.n-slider-handle-wrapper').setStyle({
    76. "left": getOffsetWidth(value),
    77. "transition": drag ? "none" : "all .2s"
    78. });
    79. ins.selectComponent('.n-slider-rail__fill').setStyle({
    80. "width": getOffsetWidth(value),
    81. "transition": drag ? "none" : "all .2s"
    82. });
    83. if (drag) {
    84. ins.triggerEvent('drag', {
    85. value: value
    86. });
    87. }
    88. if (end) {
    89. ins.triggerEvent('change', value);
    90. }
    91. if (drag || end) {
    92. // ins.callMethod('setVal', value);
    93. }
    94. }
    95. function getScope() {
    96. return Number(propValue.max) - Number(propValue.min);
    97. }
    98. function getOffsetWidth(current) {
    99. var scope = getScope();
    100. // 避免最小值小于最小step时出现负数情况
    101. return "".concat(Math.max(((current - Number(propValue.min)) * 100) / scope, 0), "%");
    102. }
    103. function percentageToValue(percentage) {
    104. return propValue.min + (propValue.max - propValue.min) * percentage
    105. }
    106. function propObserver(newValue, oldValue, ownerInstance, instance) {
    107. //这里判断一下newValue.value是否等于0,否则等于0的情况下不会执行这里
    108. if (newValue.value || newValue.value === 0) {
    109. propValue = newValue;
    110. updateValue(ownerInstance, propValue.value);
    111. }
    112. }
    113. module.exports = {
    114. onTouchStart: onTouchStart,
    115. onTouchMove: onTouchMove,
    116. onTouchEnd: onTouchEnd,
    117. onClick: onClick,
    118. propObserver: propObserver
    119. }

    wxss 

    1. .n-slider {
    2. position: relative;
    3. z-index: 0;
    4. width: 100%;
    5. /* 增大点击范围 */
    6. padding: 7px 0;
    7. }
    8. .n-slider__disabled {
    9. opacity: .5;
    10. }
    11. .n-slider .n-slider-rail {
    12. width: 100%;
    13. position: relative;
    14. height: 10rpx;
    15. background-color: rgb(219, 219, 223);
    16. border-radius: 10rpx;
    17. }
    18. .n-slider .n-slider-rail .n-slider-rail__fill {
    19. position: absolute;
    20. top: 0;
    21. bottom: 0;
    22. background-color: #FA6800;
    23. left: 0;
    24. /* 改变这个 */
    25. width: 0%;
    26. border-radius: inherit;
    27. }
    28. .n-slider .n-slider-handles {
    29. position: absolute;
    30. top: 0;
    31. bottom: 0;
    32. /* 这里是滑块宽度的一半 */
    33. left: 80rpx;
    34. right: 80rpx;
    35. }
    36. .n-slider .n-slider-handles .n-slider-handle-wrapper {
    37. outline: none;
    38. position: absolute;
    39. top: 50%;
    40. transform: translate(-50%, -50%);
    41. display: flex;
    42. /* 改变这个 */
    43. left: 0%;
    44. z-index: 0;
    45. /* transition: all .2s; */
    46. }
    47. .n-slider .n-slider-handles .n-slider-handle-wrapper .n-slider-handle {
    48. height: 42rpx;
    49. line-height: 42rpx;
    50. width: 160rpx;
    51. overflow: hidden;
    52. background-color: #FFFFFF;
    53. /* box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.3), inset 0 0 1px 0 rgba(0, 0, 0, 0.05); */
    54. opacity: .8;
    55. font-size: 26rpx;
    56. text-align: center;
    57. border: 1px solid #b9b9b9;
    58. box-sizing: border-box;
    59. border-radius: 6rpx;
    60. color: #333333;
    61. }

    如果觉得可以,请微信关注《华音有声剧社》公众号,进入小程序听书

  • 相关阅读:
    云安全(1)--初识容器逃逸之特权容器逃逸
    chrome历史版本下载
    基于准确度评估的7自由度手术机器人术前摆位优化算法
    下载文件流
    Go 初识微信订阅号(测试号)
    让1个服务开机自启动 有什么方法
    C++中为何需要函数
    缓存相关问题
    .NET应用系统的国际化-多语言词条服务
    R 语言详细安装教程(保姆级)及 RStudio简易安装教程
  • 原文地址:https://blog.csdn.net/yusha123/article/details/133080902