当前位置:   article > 正文

h5实现纵向滑动选择器选择年份组件(附完整代码)_h5 滑动日期选择器

h5 滑动日期选择器

1.背景

项目需求收集用户信息,其中包含用户的出生年月,如果让用户自己输入,体验不太友好,所以要求使用滑动选择的方式。

草稿效果图:

2.实现大致思路(最后附上完整代码)

(1)组件从父元素获取开始和结束年份,使用循环获得年份的数组:

let yearList = [this.startYear - 2, this.startYear - 1];

    for (let index = this.startYear; index <= this.endYear; index++) {

      yearList.push(index);

    }

 yearList.push(this.endYear + 1, this.endYear + 2);

this.yearList = yearList;

这里,前后分别加了两个年份,以便拖动到最开始和最后的时候能选择。即:

 (2)将数组显示到设置了可滑动的div中:

<div class="year" v-for="(year, index) in yearList" :key="index">

          {{ year }}

 </div>

这里就得到了可以滑动的年份,但是没有选中的样式以及渐变的效果。

(3)接着是实现滑动的时候选中

在设置了滑动的div中监听滑动:

<div class="year-box" @scroll.passive="scroll"></div>

passive使得滑动更平稳,监听函数:

scroll(e) {

      // e.target.scrollHeight / this.yearListLength为每个选项高度

      // e.target.scrollTop / (e.target.scrollHeight / this.yearListLength)判断滑动到哪一个选项

      this.nowScrollYear = Math.round(

        e.target.scrollTop / (e.target.scrollHeight / this.yearListLength)

      );

      this.year1 = this.nowScrollYear + this.startYear - 2;

      this.year2 = this.nowScrollYear + this.startYear - 1;

      this.year3 = this.nowScrollYear + this.startYear;

      this.year4 = this.nowScrollYear + this.startYear + 1;

      this.year5 = this.nowScrollYear + this.startYear + 2;

    },

整体思路就是获取整个滑动盒子的高度,除以选项的个数,得到每一个选项的高度,再使用滑动盒子滑动的位置,判断滑动到哪一个选项,以此得到5个选项。

(4)我们得到了滑动到那个选项,现在就是显示

<div

          class="year"

          :class="[

            year == year1 || year == year5 ? 'opcity3' : '',

            year == year2 || year == year4 ? 'opcity6' : '',

            year == year3 ? 'select' : '',

            year == startYear - 1 || year == startYear - 2 || year == endYear + 1 || year == endYear + 2 ? 'opcity0' : '',

          ]"

          v-for="(year, index) in yearList"

          :key="index"

        >

          {{ year }}

</div>

year == startYear - 1 || year == startYear - 2 || year == endYear + 1 || year == endYear + 2 ? 'opcity0' : ''  //判断是否为前后的两个选项

(5)现在基本有了大致的功能,还差一些细节,选中之后再次选择需要跳转到当前选项,需要在watch监听中做文章,思路和滑动类似

watch: {

    show: {

      handler: function (newVal) {

        if(!newVal) return;

        // 因为使用了v-if,所以需要等dom更新后才能获取

        this.$nextTick(()=>{

          let yearBox = document.getElementsByClassName("year-box")[0];

          // 需要移动的选项个数

          let needMoveNumber = this.nowYear - this.startYear;

          yearBox.scrollTop = (yearBox.scrollHeight / this.yearListLength) * needMoveNumber;

        })

      },

      deep: true,

    }

  },

3.完整代码(直接复制代码,用组件的方式使用即可)

主页面(引入后使用):

<date-picker

      :show="showDatePicker"

      :nowYear="nowYear"

      @confirm="inputYear"

      @hide="hideDataPicker"

    ></date-picker>

组件:

  1. <template>
  2. <div class="date-popup-box" v-if="show">
  3. <div class="mask" @click="hide"></div>
  4. <div class="date-box">
  5. <div class="year-box" @scroll.passive="scroll">
  6. <div
  7. class="year"
  8. :class="[
  9. year == year1 || year == year5 ? 'opcity3' : '',
  10. year == year2 || year == year4 ? 'opcity6' : '',
  11. year == year3 ? 'select' : '',
  12. year == startYear - 1 ||
  13. year == startYear - 2 ||
  14. year == endYear + 1 ||
  15. year == endYear + 2
  16. ? 'opcity0'
  17. : '',
  18. ]"
  19. v-for="(year, index) in yearList"
  20. :key="index"
  21. >
  22. {{ year }}
  23. </div>
  24. </div>
  25. <div class="btn-box">
  26. <div class="btn cancel" @click="hide"><span>Cancel</span></div>
  27. <div class="btn ok" @click="confirm"><span>OK</span></div>
  28. </div>
  29. </div>
  30. </div>
  31. </template>
  32. <script>
  33. export default {
  34. name: "datePicker",
  35. props: {
  36. show: {
  37. type: Boolean,
  38. required: true,
  39. default: false,
  40. },
  41. nowYear: {
  42. type: Number,
  43. default: 1900,
  44. },
  45. startYear: {
  46. type: Number,
  47. default: 1900,
  48. },
  49. endYear: {
  50. type: Number,
  51. default: 2021,
  52. },
  53. },
  54. data() {
  55. return {
  56. yearList: [],
  57. year1: 1900,
  58. year2: 1901,
  59. year3: 1902,
  60. year4: 1903,
  61. year5: 1904,
  62. };
  63. },
  64. watch: {
  65. show: {
  66. handler: function (newVal) {
  67. if (!newVal) return;
  68. this.$nextTick(() => {
  69. let yearBox = document.getElementsByClassName("year-box")[0];
  70. // 需要移动的选项个数
  71. let needMoveNumber = this.nowYear - this.startYear;
  72. yearBox.scrollTop =
  73. (yearBox.scrollHeight / this.yearListLength) * needMoveNumber;
  74. });
  75. },
  76. deep: true,
  77. },
  78. },
  79. mounted() {
  80. let yearList = [this.startYear - 2, this.startYear - 1];
  81. for (let index = this.startYear; index <= this.endYear; index++) {
  82. yearList.push(index);
  83. }
  84. yearList.push(this.endYear + 1, this.endYear + 2);
  85. this.yearList = yearList;
  86. this.yearListLength = yearList.length;
  87. this.year1 = this.nowYear - 2;
  88. this.year2 = this.nowYear - 1;
  89. this.year3 = this.nowYear;
  90. this.year4 = this.nowYear + 1;
  91. this.year5 = this.nowYear + 2;
  92. },
  93. methods: {
  94. confirm() {
  95. this.$emit("confirm", this.year3);
  96. },
  97. hide() {
  98. this.$emit("hide");
  99. },
  100. scroll(e) {
  101. // e.target.scrollHeight / this.yearListLength为每个选项高度
  102. // e.target.scrollTop / (e.target.scrollHeight / this.yearListLength)判断滑动到哪一个选项
  103. this.nowScrollYear = Math.round(
  104. e.target.scrollTop / (e.target.scrollHeight / this.yearListLength)
  105. );
  106. this.year1 = this.nowScrollYear + this.startYear - 2;
  107. this.year2 = this.nowScrollYear + this.startYear - 1;
  108. this.year3 = this.nowScrollYear + this.startYear;
  109. this.year4 = this.nowScrollYear + this.startYear + 1;
  110. this.year5 = this.nowScrollYear + this.startYear + 2;
  111. },
  112. },
  113. };
  114. </script>
  115. <style scoped>
  116. .date-popup-box {
  117. position: absolute;
  118. top: 0;
  119. left: 0;
  120. width: 100vw;
  121. height: 100%;
  122. }
  123. .date-popup-box .mask {
  124. width: 100vw;
  125. height: 100%;
  126. position: absolute;
  127. top: 0;
  128. left: 0;
  129. }
  130. @keyframes datePopup {
  131. from {
  132. transform: translateY(100%);
  133. opacity: 0;
  134. }
  135. to {
  136. transform: translateY(0);
  137. opacity: 1;
  138. }
  139. }
  140. .date-box {
  141. position: absolute;
  142. bottom: 0;
  143. left: 0;
  144. width: 100vw;
  145. height: 40%;
  146. color: #ffffff;
  147. background-color: #2c2c2c;
  148. border-radius: 6vw 6vw 0 0;
  149. padding: 10% 0;
  150. box-sizing: border-box;
  151. animation: datePopup 0.3s;
  152. animation-timing-function: ease-out;
  153. }
  154. .date-box .year-box {
  155. height: 80%;
  156. overflow-y: scroll;
  157. }
  158. .date-box .year-box .year {
  159. padding: 3vw;
  160. opacity: 0.1;
  161. transition: 0.1s;
  162. font-size: 4vw;
  163. }
  164. .date-box .year-box .year.opcity3 {
  165. opacity: 0.4;
  166. }
  167. .date-box .year-box .year.opcity6 {
  168. opacity: 0.7;
  169. }
  170. .date-box .year-box .year.select {
  171. font-size: 5vw;
  172. opacity: 1;
  173. }
  174. .date-box .year-box .year.opcity0 {
  175. opacity: 0;
  176. }
  177. .date-box .btn-box {
  178. display: flex;
  179. justify-content: space-between;
  180. align-items: center;
  181. width: 50vw;
  182. margin-left: 25vw;
  183. margin-top: 8vw;
  184. }
  185. .date-box .btn-box .btn {
  186. display: flex;
  187. justify-content: center;
  188. align-items: center;
  189. width: 20vw;
  190. height: 8vw;
  191. border: 0.53vw solid;
  192. border-radius: 2vw;
  193. }
  194. .date-box .btn-box .btn.cnacel {
  195. color: #ffffff;
  196. background-color: gainsboro;
  197. }
  198. .date-box .btn-box .btn.ok {
  199. color: #000;
  200. background-color: #fff;
  201. }
  202. </style>

4.结语

实现的代码比较粗糙,如有问题,欢迎交流。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/159441
推荐阅读
相关标签
  

闽ICP备14008679号