mpvuePicker.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  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. console.log(11111111, e);
  271. this.pickerValue = e.detail.value;
  272. let pickObj = {
  273. index: this.pickerValue,
  274. value: this._getPickerLabelAndValue(this.pickerValue, this.mode).value,
  275. label: this._getPickerLabelAndValue(this.pickerValue, this.mode).label
  276. };
  277. this.$emit('onChange', pickObj);
  278. },
  279. pickerChangeMul(e) {
  280. if (this.deepLength === 2) {
  281. let pickerValueArray = this.pickerValueArray;
  282. let changeValue = e.detail.value;
  283. // 处理第一列滚动
  284. if (changeValue[0] !== this.pickerValue[0]) {
  285. let pickerValueMulTwoTwo = [];
  286. // 第一列滚动第二列数据更新
  287. for (let i = 0, length = pickerValueArray[changeValue[0]].children.length; i < length; i++) {
  288. pickerValueMulTwoTwo.push(pickerValueArray[changeValue[0]].children[i]);
  289. }
  290. this.pickerValueMulTwoTwo = pickerValueMulTwoTwo;
  291. // 第二列初始化为 0
  292. changeValue[1] = 0;
  293. }
  294. this.pickerValue = changeValue;
  295. } else if (this.deepLength === 3) {
  296. let pickerValueArray = this.pickerValueArray;
  297. let changeValue = e.detail.value;
  298. let pickerValueMulThreeTwo = [];
  299. let pickerValueMulThreeThree = [];
  300. // 重新渲染第二列
  301. // 如果是第一列滚动
  302. if (changeValue[0] !== this.pickerValue[0]) {
  303. this.pickerValueMulThreeTwo = [];
  304. for (let i = 0, length = pickerValueArray[changeValue[0]].children.length; i < length; i++) {
  305. pickerValueMulThreeTwo.push(pickerValueArray[changeValue[0]].children[i]);
  306. }
  307. // 重新渲染第三列
  308. for (let i = 0, length = pickerValueArray[changeValue[0]].children[0].children.length; i <
  309. length; i++) {
  310. pickerValueMulThreeThree.push(pickerValueArray[changeValue[0]].children[0].children[i]);
  311. }
  312. changeValue[1] = 0;
  313. changeValue[2] = 0;
  314. this.pickerValueMulThreeTwo = pickerValueMulThreeTwo;
  315. this.pickerValueMulThreeThree = pickerValueMulThreeThree;
  316. } else if (changeValue[1] !== this.pickerValue[1]) {
  317. // 第二列滚动
  318. // 重新渲染第三列
  319. this.pickerValueMulThreeThree = [];
  320. pickerValueMulThreeTwo = this.pickerValueMulThreeTwo;
  321. for (let i = 0, length = pickerValueArray[changeValue[0]].children[changeValue[1]].children
  322. .length; i <
  323. length; i++) {
  324. pickerValueMulThreeThree.push(pickerValueArray[changeValue[0]].children[changeValue[1]]
  325. .children[
  326. i]);
  327. }
  328. changeValue[2] = 0;
  329. this.pickerValueMulThreeThree = pickerValueMulThreeThree;
  330. }
  331. this.pickerValue = changeValue;
  332. }
  333. let pickObj = {
  334. index: this.pickerValue,
  335. value: this._getPickerLabelAndValue(this.pickerValue, this.mode).value,
  336. label: this._getPickerLabelAndValue(this.pickerValue, this.mode).label
  337. };
  338. this.$emit('onChange', pickObj);
  339. },
  340. // 获取 pxikerLabel
  341. _getPickerLabelAndValue(value, mode) {
  342. let pickerLable;
  343. let pickerGetValue = [];
  344. // selector
  345. if (mode === 'selector') {
  346. pickerLable = this.pickerValueSingleArray[value].label;
  347. pickerGetValue.push(this.pickerValueSingleArray[value].value);
  348. } else if (mode === 'timeSelector') {
  349. pickerLable = `${this.pickerValueHour[value[0]].label}-${this.pickerValueMinute[value[1]].label}`;
  350. pickerGetValue.push(this.pickerValueHour[value[0]].value);
  351. pickerGetValue.push(this.pickerValueHour[value[1]].value);
  352. } else if (mode === 'multiSelector') {
  353. for (let i = 0; i < value.length; i++) {
  354. if (i > 0) {
  355. pickerLable += this.pickerValueMulArray[i][value[i]].label + (i === value.length - 1 ? '' :
  356. '-');
  357. } else {
  358. pickerLable = this.pickerValueMulArray[i][value[i]].label + '-';
  359. }
  360. pickerGetValue.push(this.pickerValueMulArray[i][value[i]].value);
  361. }
  362. } else if (mode === 'multiLinkageSelector') {
  363. /* eslint-disable indent */
  364. pickerLable =
  365. this.deepLength === 2 ?
  366. `${this.pickerValueMulTwoOne[value[0]].label}-${this.pickerValueMulTwoTwo[value[1]].label}` :
  367. `${this.pickerValueMulThreeOne[value[0]].label}-${this.pickerValueMulThreeTwo[value[1]].label}-${this.pickerValueMulThreeThree[value[2]].label}`;
  368. if (this.deepLength === 2) {
  369. pickerGetValue.push(this.pickerValueMulTwoOne[value[0]].value);
  370. pickerGetValue.push(this.pickerValueMulTwoTwo[value[1]].value);
  371. } else {
  372. pickerGetValue.push(this.pickerValueMulThreeOne[value[0]].value);
  373. pickerGetValue.push(this.pickerValueMulThreeTwo[value[1]].value);
  374. pickerGetValue.push(this.pickerValueMulThreeThree[value[2]].value);
  375. }
  376. /* eslint-enable indent */
  377. }
  378. return {
  379. label: pickerLable,
  380. value: pickerGetValue
  381. };
  382. },
  383. // 初始化 pickerValue 默认值
  384. _initPickerVale() {
  385. if (this.pickerValue.length === 0) {
  386. if (this.mode === 'selector') {
  387. this.pickerValue = [0];
  388. } else if (this.mode === 'multiSelector') {
  389. this.pickerValue = new Int8Array(this.pickerValueArray.length);
  390. } else if (
  391. this.mode === 'multiLinkageSelector' &&
  392. this.deepLength === 2
  393. ) {
  394. this.pickerValue = [0, 0];
  395. } else if (
  396. this.mode === 'multiLinkageSelector' &&
  397. this.deepLength === 3
  398. ) {
  399. this.pickerValue = [0, 0, 0];
  400. }
  401. }
  402. }
  403. }
  404. };
  405. </script>
  406. <style>
  407. .pickerMask {
  408. position: fixed;
  409. z-index: 1000;
  410. top: 0;
  411. right: 0;
  412. left: 0;
  413. bottom: 0;
  414. background: rgba(0, 0, 0, 0.6);
  415. }
  416. .mpvue-picker-content {
  417. position: fixed;
  418. bottom: 0;
  419. left: 0;
  420. width: 100%;
  421. transition: all 0.3s ease;
  422. transform: translateY(100%);
  423. z-index: 3000;
  424. }
  425. .mpvue-picker-view-show {
  426. transform: translateY(0);
  427. }
  428. .mpvue-picker__hd {
  429. display: flex;
  430. padding: 9px 15px;
  431. background-color: #fff;
  432. position: relative;
  433. text-align: center;
  434. font-size: 17px;
  435. }
  436. .mpvue-picker__hd:after {
  437. content: ' ';
  438. position: absolute;
  439. left: 0;
  440. bottom: 0;
  441. right: 0;
  442. height: 1px;
  443. border-bottom: 1px solid #e5e5e5;
  444. color: #e5e5e5;
  445. transform-origin: 0 100%;
  446. transform: scaleY(0.5);
  447. }
  448. .mpvue-picker__action {
  449. display: block;
  450. flex: 1;
  451. color: #1aad19;
  452. }
  453. .mpvue-picker__action:first-child {
  454. text-align: left;
  455. color: #888;
  456. }
  457. .mpvue-picker__action:last-child {
  458. text-align: right;
  459. }
  460. .picker-item {
  461. text-align: center;
  462. line-height: 40px;
  463. font-size: 16px;
  464. }
  465. .mpvue-picker-view {
  466. position: relative;
  467. bottom: 0;
  468. left: 0;
  469. width: 100%;
  470. height: 238px;
  471. background-color: rgba(255, 255, 255, 1);
  472. }
  473. </style>