mpvuePicker.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. <template>
  2. <view class="mpvue-picker">
  3. <view :class="{'pickerMask':showPicker}" @click="maskClick" catchtouchmove="true"></view>
  4. <view class="mpvue-picker-content " :class="{'mpvue-picker-view-show':showPicker}">
  5. <view class="mpvue-picker__hd" catchtouchmove="true">
  6. <view class="mpvue-picker__action" @click="pickerCancel">取消</view>
  7. <view class="mpvue-picker__action" :style="{color:themeColor}" @click="pickerConfirm">确定</view>
  8. </view>
  9. <!-- 单列 -->
  10. <picker-view indicator-style="height: 40px;" class="mpvue-picker-view" :value="pickerValue"
  11. @change="pickerChange" v-if="mode==='selector' && pickerValueSingleArray.length > 0">
  12. <picker-view-column>
  13. <view class="picker-item" v-for="(item,index) in pickerValueSingleArray" :key="index">{{item.label}}
  14. </view>
  15. </picker-view-column>
  16. </picker-view>
  17. <!-- 时间选择器 -->
  18. <picker-view indicator-style="height: 40px;" class="mpvue-picker-view" :value="pickerValue"
  19. @change="pickerChange" v-if="mode==='timeSelector'">
  20. <picker-view-column>
  21. <view class="picker-item" v-for="(item,index) in pickerValueHour" :key="index">{{item.label}}</view>
  22. </picker-view-column>
  23. <picker-view-column>
  24. <view class="picker-item" v-for="(item,index) in pickerValueMinute" :key="index">{{item.label}}
  25. </view>
  26. </picker-view-column>
  27. </picker-view>
  28. <!-- 多列选择 -->
  29. <picker-view indicator-style="height: 40px;" class="mpvue-picker-view" :value="pickerValue"
  30. @change="pickerChange" v-if="mode==='multiSelector'">
  31. <!-- #ifdef VUE3 -->
  32. <template v-for="(n,index) in pickerValueMulArray.length" :key="index">
  33. <picker-view-column>
  34. <view class="picker-item" v-for="(item,index1) in pickerValueMulArray[n]" :key="index1">
  35. {{item.label}}
  36. </view>
  37. </picker-view-column>
  38. </template>
  39. <!-- #endif -->
  40. <!-- #ifndef VUE3 -->
  41. <block v-for="(n,index) in pickerValueMulArray.length" :key="index">
  42. <picker-view-column>
  43. <view class="picker-item" v-for="(item,index1) in pickerValueMulArray[n]" :key="index1">
  44. {{item.label}}
  45. </view>
  46. </picker-view-column>
  47. </block>
  48. <!-- #endif -->
  49. </picker-view>
  50. <!-- 二级联动 -->
  51. <picker-view indicator-style="height: 40px;" class="mpvue-picker-view" :value="pickerValue"
  52. @change="pickerChangeMul" v-if="mode==='multiLinkageSelector' && deepLength===2">
  53. <picker-view-column>
  54. <view class="picker-item" v-for="(item,index) in pickerValueMulTwoOne" :key="index">{{item.label}}
  55. </view>
  56. </picker-view-column>
  57. <picker-view-column>
  58. <view class="picker-item" v-for="(item,index) in pickerValueMulTwoTwo" :key="index">{{item.label}}
  59. </view>
  60. </picker-view-column>
  61. </picker-view>
  62. <!-- 三级联动 -->
  63. <picker-view indicator-style="height: 40px;" class="mpvue-picker-view" :value="pickerValue"
  64. @change="pickerChangeMul" v-if="mode==='multiLinkageSelector' && deepLength===3">
  65. <picker-view-column>
  66. <view class="picker-item" v-for="(item,index) in pickerValueMulThreeOne" :key="index">{{item.label}}
  67. </view>
  68. </picker-view-column>
  69. <picker-view-column>
  70. <view class="picker-item" v-for="(item,index) in pickerValueMulThreeTwo" :key="index">{{item.label}}
  71. </view>
  72. </picker-view-column>
  73. <picker-view-column>
  74. <view class="picker-item" v-for="(item,index) in pickerValueMulThreeThree" :key="index">
  75. {{item.label}}
  76. </view>
  77. </picker-view-column>
  78. </picker-view>
  79. </view>
  80. </view>
  81. </template>
  82. <script>
  83. export default {
  84. data() {
  85. return {
  86. pickerChangeValue: [],
  87. pickerValue: [],
  88. pickerValueArrayChange: true,
  89. modeChange: false,
  90. pickerValueSingleArray: [],
  91. pickerValueHour: [],
  92. pickerValueMinute: [],
  93. pickerValueMulArray: [],
  94. pickerValueMulTwoOne: [],
  95. pickerValueMulTwoTwo: [],
  96. pickerValueMulThreeOne: [],
  97. pickerValueMulThreeTwo: [],
  98. pickerValueMulThreeThree: [],
  99. /* 是否显示控件 */
  100. showPicker: false,
  101. };
  102. },
  103. props: {
  104. /* mode */
  105. mode: {
  106. type: String,
  107. default: 'selector'
  108. },
  109. /* picker 数值 */
  110. pickerValueArray: {
  111. type: Array,
  112. default () {
  113. return []
  114. }
  115. },
  116. /* 默认值 */
  117. pickerValueDefault: {
  118. type: Array,
  119. default () {
  120. return []
  121. }
  122. },
  123. /* 几级联动 */
  124. deepLength: {
  125. type: Number,
  126. default: 2
  127. },
  128. /* 主题色 */
  129. themeColor: String
  130. },
  131. watch: {
  132. pickerValueArray(oldVal, newVal) {
  133. this.pickerValueArrayChange = true;
  134. },
  135. mode(oldVal, newVal) {
  136. this.modeChange = true;
  137. },
  138. pickerValueArray(val) {
  139. this.initPicker(val);
  140. }
  141. },
  142. methods: {
  143. initPicker(valueArray) {
  144. let pickerValueArray = valueArray;
  145. this.pickerValue = this.pickerValueDefault;
  146. // 初始化多级联动
  147. if (this.mode === 'selector') {
  148. this.pickerValueSingleArray = valueArray;
  149. } else if (this.mode === 'timeSelector') {
  150. this.modeChange = false;
  151. let hourArray = [];
  152. let minuteArray = [];
  153. for (let i = 0; i < 24; i++) {
  154. hourArray.push({
  155. value: i,
  156. label: i > 9 ? `${i} 时` : `0${i} 时`
  157. });
  158. }
  159. for (let i = 0; i < 60; i++) {
  160. minuteArray.push({
  161. value: i,
  162. label: i > 9 ? `${i} 分` : `0${i} 分`
  163. });
  164. }
  165. this.pickerValueHour = hourArray;
  166. this.pickerValueMinute = minuteArray;
  167. } else if (this.mode === 'multiSelector') {
  168. this.pickerValueMulArray = valueArray;
  169. } else if (this.mode === 'multiLinkageSelector' && this.deepLength === 2) {
  170. // 两级联动
  171. let pickerValueMulTwoOne = [];
  172. let pickerValueMulTwoTwo = [];
  173. // 第一列
  174. for (let i = 0, length = pickerValueArray.length; i < length; i++) {
  175. pickerValueMulTwoOne.push(pickerValueArray[i]);
  176. }
  177. // 渲染第二列
  178. // 如果有设定的默认值
  179. if (this.pickerValueDefault.length === 2) {
  180. let num = this.pickerValueDefault[0];
  181. for (
  182. let i = 0, length = pickerValueArray[num].children.length; i < length; i++
  183. ) {
  184. pickerValueMulTwoTwo.push(pickerValueArray[num].children[i]);
  185. }
  186. } else {
  187. for (
  188. let i = 0, length = pickerValueArray[0].children.length; i < length; i++
  189. ) {
  190. pickerValueMulTwoTwo.push(pickerValueArray[0].children[i]);
  191. }
  192. }
  193. this.pickerValueMulTwoOne = pickerValueMulTwoOne;
  194. this.pickerValueMulTwoTwo = pickerValueMulTwoTwo;
  195. } else if (
  196. this.mode === 'multiLinkageSelector' &&
  197. this.deepLength === 3
  198. ) {
  199. let pickerValueMulThreeOne = [];
  200. let pickerValueMulThreeTwo = [];
  201. let pickerValueMulThreeThree = [];
  202. // 第一列
  203. for (let i = 0, length = pickerValueArray.length; i < length; i++) {
  204. pickerValueMulThreeOne.push(pickerValueArray[i]);
  205. }
  206. // 渲染第二列
  207. this.pickerValueDefault =
  208. this.pickerValueDefault.length === 3 ?
  209. this.pickerValueDefault : [0, 0, 0];
  210. if (this.pickerValueDefault.length === 3) {
  211. let num = this.pickerValueDefault[0];
  212. for (
  213. let i = 0, length = pickerValueArray[num].children.length; i < length; i++
  214. ) {
  215. pickerValueMulThreeTwo.push(pickerValueArray[num].children[i]);
  216. }
  217. // 第三列
  218. let numSecond = this.pickerValueDefault[1];
  219. for (let i = 0, length = pickerValueArray[num].children[numSecond].children.length; i <
  220. length; i++) {
  221. pickerValueMulThreeThree.push(
  222. pickerValueArray[num].children[numSecond].children[i]
  223. );
  224. }
  225. }
  226. this.pickerValueMulThreeOne = pickerValueMulThreeOne;
  227. this.pickerValueMulThreeTwo = pickerValueMulThreeTwo;
  228. this.pickerValueMulThreeThree = pickerValueMulThreeThree;
  229. }
  230. },
  231. show() {
  232. setTimeout(() => {
  233. if (this.pickerValueArrayChange || this.modeChange) {
  234. this.initPicker(this.pickerValueArray);
  235. this.showPicker = true;
  236. this.pickerValueArrayChange = false;
  237. this.modeChange = false;
  238. } else {
  239. this.showPicker = true;
  240. }
  241. }, 0);
  242. },
  243. maskClick() {
  244. this.pickerCancel();
  245. },
  246. pickerCancel() {
  247. this.showPicker = false;
  248. this._initPickerVale();
  249. let pickObj = {
  250. index: this.pickerValue,
  251. value: this._getPickerLabelAndValue(this.pickerValue, this.mode).value,
  252. label: this._getPickerLabelAndValue(this.pickerValue, this.mode).label
  253. };
  254. this.$emit('onCancel', pickObj);
  255. },
  256. pickerConfirm(e) {
  257. this.showPicker = false;
  258. this._initPickerVale();
  259. let pickObj = {
  260. index: this.pickerValue,
  261. value: this._getPickerLabelAndValue(this.pickerValue, this.mode).value,
  262. label: this._getPickerLabelAndValue(this.pickerValue, this.mode).label
  263. };
  264. this.$emit('onConfirm', pickObj);
  265. },
  266. showPickerView() {
  267. this.showPicker = true;
  268. },
  269. pickerChange(e) {
  270. this.pickerValue = e.mp.detail.value;
  271. let pickObj = {
  272. index: this.pickerValue,
  273. value: this._getPickerLabelAndValue(this.pickerValue, this.mode).value,
  274. label: this._getPickerLabelAndValue(this.pickerValue, this.mode).label
  275. };
  276. this.$emit('onChange', pickObj);
  277. },
  278. pickerChangeMul(e) {
  279. if (this.deepLength === 2) {
  280. let pickerValueArray = this.pickerValueArray;
  281. let changeValue = e.mp.detail.value;
  282. // 处理第一列滚动
  283. if (changeValue[0] !== this.pickerValue[0]) {
  284. let pickerValueMulTwoTwo = [];
  285. // 第一列滚动第二列数据更新
  286. for (let i = 0, length = pickerValueArray[changeValue[0]].children.length; i < length; i++) {
  287. pickerValueMulTwoTwo.push(pickerValueArray[changeValue[0]].children[i]);
  288. }
  289. this.pickerValueMulTwoTwo = pickerValueMulTwoTwo;
  290. // 第二列初始化为 0
  291. changeValue[1] = 0;
  292. }
  293. this.pickerValue = changeValue;
  294. } else if (this.deepLength === 3) {
  295. let pickerValueArray = this.pickerValueArray;
  296. let changeValue = e.mp.detail.value;
  297. let pickerValueMulThreeTwo = [];
  298. let pickerValueMulThreeThree = [];
  299. // 重新渲染第二列
  300. // 如果是第一列滚动
  301. if (changeValue[0] !== this.pickerValue[0]) {
  302. this.pickerValueMulThreeTwo = [];
  303. for (let i = 0, length = pickerValueArray[changeValue[0]].children.length; i < length; i++) {
  304. pickerValueMulThreeTwo.push(pickerValueArray[changeValue[0]].children[i]);
  305. }
  306. // 重新渲染第三列
  307. for (let i = 0, length = pickerValueArray[changeValue[0]].children[0].children.length; i <
  308. length; i++) {
  309. pickerValueMulThreeThree.push(pickerValueArray[changeValue[0]].children[0].children[i]);
  310. }
  311. changeValue[1] = 0;
  312. changeValue[2] = 0;
  313. this.pickerValueMulThreeTwo = pickerValueMulThreeTwo;
  314. this.pickerValueMulThreeThree = pickerValueMulThreeThree;
  315. } else if (changeValue[1] !== this.pickerValue[1]) {
  316. // 第二列滚动
  317. // 重新渲染第三列
  318. this.pickerValueMulThreeThree = [];
  319. pickerValueMulThreeTwo = this.pickerValueMulThreeTwo;
  320. for (let i = 0, length = pickerValueArray[changeValue[0]].children[changeValue[1]].children
  321. .length; i <
  322. length; i++) {
  323. pickerValueMulThreeThree.push(pickerValueArray[changeValue[0]].children[changeValue[1]]
  324. .children[
  325. i]);
  326. }
  327. changeValue[2] = 0;
  328. this.pickerValueMulThreeThree = pickerValueMulThreeThree;
  329. }
  330. this.pickerValue = changeValue;
  331. }
  332. let pickObj = {
  333. index: this.pickerValue,
  334. value: this._getPickerLabelAndValue(this.pickerValue, this.mode).value,
  335. label: this._getPickerLabelAndValue(this.pickerValue, this.mode).label
  336. };
  337. this.$emit('onChange', pickObj);
  338. },
  339. // 获取 pxikerLabel
  340. _getPickerLabelAndValue(value, mode) {
  341. let pickerLable;
  342. let pickerGetValue = [];
  343. // selector
  344. if (mode === 'selector') {
  345. pickerLable = this.pickerValueSingleArray[value].label;
  346. pickerGetValue.push(this.pickerValueSingleArray[value].value);
  347. } else if (mode === 'timeSelector') {
  348. pickerLable = `${this.pickerValueHour[value[0]].label}-${this.pickerValueMinute[value[1]].label}`;
  349. pickerGetValue.push(this.pickerValueHour[value[0]].value);
  350. pickerGetValue.push(this.pickerValueHour[value[1]].value);
  351. } else if (mode === 'multiSelector') {
  352. for (let i = 0; i < value.length; i++) {
  353. if (i > 0) {
  354. pickerLable += this.pickerValueMulArray[i][value[i]].label + (i === value.length - 1 ? '' :
  355. '-');
  356. } else {
  357. pickerLable = this.pickerValueMulArray[i][value[i]].label + '-';
  358. }
  359. pickerGetValue.push(this.pickerValueMulArray[i][value[i]].value);
  360. }
  361. } else if (mode === 'multiLinkageSelector') {
  362. /* eslint-disable indent */
  363. pickerLable =
  364. this.deepLength === 2 ?
  365. `${this.pickerValueMulTwoOne[value[0]].label}-${this.pickerValueMulTwoTwo[value[1]].label}` :
  366. `${this.pickerValueMulThreeOne[value[0]].label}-${this.pickerValueMulThreeTwo[value[1]].label}-${this.pickerValueMulThreeThree[value[2]].label}`;
  367. if (this.deepLength === 2) {
  368. pickerGetValue.push(this.pickerValueMulTwoOne[value[0]].value);
  369. pickerGetValue.push(this.pickerValueMulTwoTwo[value[1]].value);
  370. } else {
  371. pickerGetValue.push(this.pickerValueMulThreeOne[value[0]].value);
  372. pickerGetValue.push(this.pickerValueMulThreeTwo[value[1]].value);
  373. pickerGetValue.push(this.pickerValueMulThreeThree[value[2]].value);
  374. }
  375. /* eslint-enable indent */
  376. }
  377. return {
  378. label: pickerLable,
  379. value: pickerGetValue
  380. };
  381. },
  382. // 初始化 pickerValue 默认值
  383. _initPickerVale() {
  384. if (this.pickerValue.length === 0) {
  385. if (this.mode === 'selector') {
  386. this.pickerValue = [0];
  387. } else if (this.mode === 'multiSelector') {
  388. this.pickerValue = new Int8Array(this.pickerValueArray.length);
  389. } else if (
  390. this.mode === 'multiLinkageSelector' &&
  391. this.deepLength === 2
  392. ) {
  393. this.pickerValue = [0, 0];
  394. } else if (
  395. this.mode === 'multiLinkageSelector' &&
  396. this.deepLength === 3
  397. ) {
  398. this.pickerValue = [0, 0, 0];
  399. }
  400. }
  401. }
  402. }
  403. };
  404. </script>
  405. <style>
  406. .pickerMask {
  407. position: fixed;
  408. z-index: 1000;
  409. top: 0;
  410. right: 0;
  411. left: 0;
  412. bottom: 0;
  413. background: rgba(0, 0, 0, 0.6);
  414. }
  415. .mpvue-picker-content {
  416. position: fixed;
  417. bottom: 0;
  418. left: 0;
  419. width: 100%;
  420. transition: all 0.3s ease;
  421. transform: translateY(100%);
  422. z-index: 3000;
  423. }
  424. .mpvue-picker-view-show {
  425. transform: translateY(0);
  426. }
  427. .mpvue-picker__hd {
  428. display: flex;
  429. padding: 9px 15px;
  430. background-color: #fff;
  431. position: relative;
  432. text-align: center;
  433. font-size: 17px;
  434. }
  435. .mpvue-picker__hd:after {
  436. content: ' ';
  437. position: absolute;
  438. left: 0;
  439. bottom: 0;
  440. right: 0;
  441. height: 1px;
  442. border-bottom: 1px solid #e5e5e5;
  443. color: #e5e5e5;
  444. transform-origin: 0 100%;
  445. transform: scaleY(0.5);
  446. }
  447. .mpvue-picker__action {
  448. display: block;
  449. flex: 1;
  450. color: #1aad19;
  451. }
  452. .mpvue-picker__action:first-child {
  453. text-align: left;
  454. color: #888;
  455. }
  456. .mpvue-picker__action:last-child {
  457. text-align: right;
  458. }
  459. .picker-item {
  460. text-align: center;
  461. line-height: 40px;
  462. font-size: 16px;
  463. }
  464. .mpvue-picker-view {
  465. position: relative;
  466. bottom: 0;
  467. left: 0;
  468. width: 100%;
  469. height: 238px;
  470. background-color: rgba(255, 255, 255, 1);
  471. }
  472. </style>