tm-pickersViewsss.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. <template>
  2. <view class="tm-pickersView flex-start px-24" :class="[black_tmeme?'grey-darken-5':bgColor]">
  3. <view v-for="(item_data,index_pub) in listData" :key="index_pub" class="tm-pickersView-wk " :style="{
  4. height:itemHeight*5+'px',
  5. width:(100/gridNum-1) + '%',
  6. marginLeft:index_pub==0?0:1.5 + '%',
  7. }">
  8. <scroll-view :show-scrollbar='false'
  9. v-if="dataType!==null&&item_data"
  10. :scroll-top="listIndex[index_pub].wz" scroll-y
  11. @touchend="scrllEnd"
  12. @scroll="scroll($event,index_pub)"
  13. scroll-with-animation
  14. class="tm-pickersView-showbg" :style="{
  15. height:itemHeight*5+'px'
  16. }">
  17. <!-- #ifdef H5 -->
  18. <view :id='"_bar_"+(index4)+"_bar_"' v-for="(item4,index4) in 2" :key="index4+'_a'" class="tm-pickersView-item "
  19. :style="{height:itemHeight+'px'}">
  20. <text class="opacity-1"></text>
  21. </view>
  22. <!-- #endif -->
  23. <!-- #ifndef H5 -->
  24. <view :id='"_bar_"+(index4)+"_bar_"' v-for="(item4,index4) in 2" :key="index4" class="tm-pickersView-item "
  25. :style="{height:itemHeight+'px'}">
  26. <text class="opacity-1"></text>
  27. </view>
  28. <!-- #endif -->
  29. <view :id='"_bar_"+(index+2)+"_bar_"' v-for="(item,index) in item_data" :key="index"
  30. class="tm-pickersView-item flex-center " :style="{
  31. height:itemHeight+'px'
  32. }">
  33. <view class="text-size-n tm-pickersView-item-text " :class="[
  34. listIndex[index_pub].itemIndex==index? (black_tmeme?'text-white':'text-black'):(black_tmeme?'':'opacity-4'),
  35. listIndex[index_pub].itemIndex+1==index||listIndex[index_pub].itemIndex-1==index?'textLevel_1':'',
  36. listIndex[index_pub].itemIndex+2==index||listIndex[index_pub].itemIndex-2==index?'textLevel_2':'',
  37. ]">
  38. <text v-if="dataType === 'string'">{{item}}</text>
  39. <text v-if="dataType === 'object'">{{item[rangKey]}}</text>
  40. </view>
  41. </view>
  42. <!-- #ifdef H5 -->
  43. <view v-for="(item4,index4) in 2" :key="index4+'_b'" class="tm-pickersView-item"
  44. :style="{height:itemHeight+'px'}">
  45. <text></text>
  46. </view>
  47. <!-- #endif -->
  48. <!-- #ifndef H5 -->
  49. <view v-for="(item4,index4) in 2" :key="index4" class="tm-pickersView-item"
  50. :style="{height:itemHeight+'px'}">
  51. <text></text>
  52. </view>
  53. <!-- #endif -->
  54. </scroll-view>
  55. <view class="tm-pickersView-fg overflow round-5 shadow-10 flex-center" :class="[
  56. black_tmeme?'white opacity-1':'grey-darken-1 opacity-1'
  57. ]" :style="{
  58. height:itemHeight+'px',
  59. top:itemHeight*2+'px'
  60. }">
  61. </view>
  62. </view>
  63. </view>
  64. </template>
  65. <script>
  66. /**
  67. * 普通级联拉选择器(嵌入式)
  68. * @description 多级关联,单级关联选择
  69. * @property {Array} default-value = [] 默认:[],默认赋值项。可选三种赋值方式,名称赋值,对象赋值,数字序列赋值
  70. * @property {String|Number} item-height = [34|42|50|58|62] 项目的高度单位px
  71. * @property {Array} list = [] 选择器的数据,可选格式:Array<string>,Array<object>.如果为object格式需要提供rangKey.如果为多级需要提供children.key值
  72. * @property {String} rang-key = [text|title] 默认:text,如果List格式为对象数组,需要提供此值
  73. * @property {String} children-key = [children] 默认:children,如果List格式为对象数组且为多级联选择,需要提供此值,理论上无限级联数据
  74. * @property {String|Boolean} black = [true|false] 是否开启暗黑模式。
  75. * @property {String|Boolean} disabled = [true|false] 是否禁用
  76. * @property {String} bg-color = [white|blue] 默认:white,白色背景;请填写背景的主题色名称。
  77. *
  78. */
  79. export default {
  80. name: "tm-pickersView",
  81. props: {
  82. // 默认选中的项
  83. // 格式有三种分别是[string,string...]
  84. // [数字序列,数字序列....]
  85. // 和list同等对象结构[{},{},...],此格式需要提供rangKey字段否则报错。
  86. defaultValue:{
  87. type:Array,
  88. default:()=>{return []}
  89. },
  90. // 行高。
  91. itemHeight: {
  92. type: String | Number,
  93. default: 40
  94. },
  95. list: {
  96. type: Array,
  97. default: () => {
  98. return []
  99. }
  100. },
  101. // 如果数据是对象,则需要提供key值。
  102. rangKey: {
  103. type: String,
  104. default: "text"
  105. },
  106. rangKeyId: {
  107. type: String,
  108. default: "id"
  109. },
  110. // 如果是联级,则需要提供子集key值。
  111. childrenKey: {
  112. type: String,
  113. default: "children"
  114. },
  115. black:{
  116. type:String|Boolean,
  117. default:null
  118. },
  119. // 是否禁用
  120. disabled:{
  121. type:String|Boolean,
  122. default:false
  123. },
  124. // 背景颜色,主题色名称。
  125. bgColor:{
  126. type:String,
  127. default:'white'
  128. }
  129. },
  130. data() {
  131. return {
  132. scrollEvent: 0,
  133. childrenIndex: 0,
  134. listIndex: [],
  135. listData: [],
  136. isTounch:false,
  137. idx:9123
  138. };
  139. },
  140. mounted() {
  141. this.$nextTick(function(){
  142. this.chulisdata()
  143. this.setDefaultValue();
  144. })
  145. },
  146. watch:{
  147. defaultValue:{
  148. deep:true,
  149. handler: function(newV,oldV){
  150. this.setDefaultValue();
  151. }
  152. },
  153. list:{
  154. deep:true,
  155. handler:function(newV,oldV){
  156. this.chulisdata()
  157. this.setDefaultValue();
  158. }
  159. },
  160. },
  161. computed: {
  162. black_tmeme: function() {
  163. if (this.black !== null) return this.black;
  164. return this.$tm.vx.state().tmVuetify.black;
  165. },
  166. dataType: function() {
  167. // 数据有误
  168. if (typeof this.list !== 'object' && !Array.isArray(this.list) && !this.list.length) return null;
  169. if (typeof this.list[0] === 'string') return 'string';
  170. if (typeof this.list[0] === 'object') return 'object';
  171. },
  172. gridNum: function() {
  173. let t = this;
  174. if (typeof this.list !== 'object' && !Array.isArray(this.list) && !this.list.length) {
  175. this.listIndex = [{
  176. itemIndex: 0,
  177. childrenIndex: 0,
  178. wz: 0
  179. }]
  180. return 0
  181. };
  182. if (typeof this.list[0] === 'string') {
  183. this.listIndex = [{
  184. itemIndex: 0,
  185. childrenIndex: 0,
  186. wz: 0
  187. }]
  188. return 1
  189. }
  190. if (typeof this.list[0] === 'object') {
  191. let index = 1;
  192. function tests(obj) {
  193. t.listIndex.push({
  194. itemIndex: 0,
  195. childrenIndex: index,
  196. wz: 0
  197. })
  198. if (obj && typeof obj === 'object' && Array.isArray(obj)) {
  199. index++
  200. if (obj[0][t.childrenKey]) {
  201. tests(obj[0][t.childrenKey]);
  202. }
  203. }
  204. }
  205. this.listIndex = [{
  206. itemIndex: 0,
  207. childrenIndex: 0,
  208. wz: 0
  209. }]
  210. tests(this.list[0][this.childrenKey])
  211. return index;
  212. }
  213. },
  214. },
  215. methods: {
  216. // 获取当前选中的数据。
  217. getSelectedValue(){
  218. let t = this;
  219. // 总的级联数。
  220. let dNum = this.gridNum;
  221. let pd = this.listIndex;
  222. if(this.dataType === 'string'){
  223. // let ps = {...this.listData[0][this.listIndex[0].itemIndex]};
  224. return [{
  225. index:this.listIndex[0].itemIndex,
  226. data:this.listData[0][this.listIndex[0].itemIndex]
  227. }]
  228. }else if(this.dataType === 'object'){
  229. if(dNum===1){
  230. let ps = {...this.listData[0][this.listIndex[0].itemIndex]};
  231. delete ps.children;
  232. return [{
  233. index:this.listIndex[0].itemIndex,
  234. data:ps
  235. }]
  236. }else if(dNum>1){
  237. let p = [];
  238. this.listIndex.forEach((item,index)=>{
  239. if(t.listData[index]){
  240. let ps = {...t.listData[index][item.itemIndex]};
  241. delete ps.children;
  242. p.push({
  243. index:item.itemIndex,
  244. data:ps
  245. })
  246. }
  247. })
  248. return p;
  249. }
  250. }
  251. return [];
  252. },
  253. chulisdata() {
  254. // 总的级联数。
  255. let dNum = this.gridNum;
  256. let t = this;
  257. if (dNum === 0) {
  258. this.listData = [];
  259. return this.listData;
  260. }
  261. if (dNum === 1) {
  262. this.listData = [];
  263. this.listData.push([...this.list]);
  264. return this.listData;
  265. }
  266. if (dNum > 1) {
  267. let index = 1;
  268. let list = [];
  269. let p = [];
  270. function tests(obj) {
  271. if(index > dNum) return;
  272. list.push([...obj])
  273. if(obj[t.listIndex[index]?.itemIndex]){
  274. let cl = obj[t.listIndex[index].itemIndex][t.childrenKey];
  275. if (cl && typeof cl === 'object' && Array.isArray(cl)) {
  276. index++;
  277. tests(cl);
  278. }
  279. }
  280. }
  281. p.push([...this.list])
  282. if(this.list[t.listIndex[0].itemIndex][this.childrenKey]){
  283. tests(this.list[t.listIndex[0].itemIndex][this.childrenKey])
  284. }
  285. p.push(...list);
  286. this.listData = p;
  287. }
  288. return this.listData;
  289. },
  290. async setDefaultValue(objSelected){
  291. // 总的级联数。
  292. let dNum = this.gridNum;
  293. let t = this;
  294. var sjd = null;
  295. if(typeof objSelected ==='object' && Array.isArray(objSelected)){
  296. sjd = objSelected;
  297. }else{
  298. if(!this.defaultValue||this.defaultValue.length==0) return;
  299. sjd = this.defaultValue;
  300. }
  301. let typeindex = typeof sjd[0];
  302. if(dNum===0) return;
  303. if(typeindex === 'number'){
  304. if (dNum === 1) {
  305. let itemIndex = sjd[0];
  306. if(typeof itemIndex === 'number' && !isNaN(itemIndex) ){
  307. this.$set(this.listIndex[0], 'itemIndex', itemIndex);
  308. this.$set(t.listIndex[0], 'wz', itemIndex * t.itemHeight);
  309. }
  310. return
  311. }else if(dNum > 1){
  312. let index = 1;
  313. async function tests() {
  314. if(index > dNum) return;
  315. let itemIndex = t.defaultValue[index];
  316. if(typeof itemIndex === 'number' && !isNaN(itemIndex) &&typeof t.listIndex[index] === 'object' && typeof t.listIndex[index] !=='undefined'){
  317. await uni.$tm.sleep(30)
  318. t.$set(t.listIndex[index], 'itemIndex', itemIndex);
  319. t.$set(t.listIndex[index], 'wz', itemIndex * t.itemHeight);
  320. t.chulisdata();
  321. index++;
  322. await tests();
  323. }
  324. }
  325. let itemIndex = sjd[0];
  326. this.$set(this.listIndex[0], 'itemIndex', itemIndex);
  327. this.$set(t.listIndex[0], 'wz', itemIndex * t.itemHeight);
  328. this.chulisdata();
  329. await tests()
  330. }
  331. }else if(typeindex === 'string'){
  332. if(this.dataType==='string'){
  333. if (dNum === 1) {
  334. let valueStr = sjd[0];
  335. if(typeof valueStr !=='string' || typeof valueStr ==='undefined' || valueStr ==null){
  336. return;
  337. }
  338. let itemIndex = this.listData[0].indexOf(valueStr)
  339. if(itemIndex>-1){
  340. this.$set(this.listIndex[0], 'itemIndex', itemIndex);
  341. this.$set(t.listIndex[0], 'wz', itemIndex * t.itemHeight);
  342. }
  343. return
  344. }
  345. }else if(this.dataType === 'object'){
  346. if (dNum === 1) {
  347. let valueStr = sjd[0];
  348. if(typeof valueStr !=='string' || typeof valueStr ==='undefined' || valueStr ==null){
  349. return;
  350. }
  351. let itemIndex = this.listData[0].findIndex(item=>{
  352. return item[t.rangKey] == valueStr;
  353. })
  354. if(itemIndex>-1){
  355. this.$set(this.listIndex[0], 'itemIndex', itemIndex);
  356. this.$set(t.listIndex[0], 'wz', itemIndex * t.itemHeight);
  357. }
  358. return
  359. }else if(dNum>1){
  360. let index = 0;
  361. async function tests() {
  362. if(index > dNum) return;
  363. if(typeof t.listIndex[index] === 'object' && typeof t.listIndex[index] !=='undefined'){
  364. let valueStr = t.defaultValue[index];
  365. if(typeof valueStr !=='string' || typeof valueStr ==='undefined' || valueStr ==null){
  366. return;
  367. }
  368. let itemIndex = t.listData[index].findIndex(item=>{
  369. return item[t.rangKey] == valueStr;
  370. })
  371. if(itemIndex>-1){
  372. await uni.$tm.sleep(30)
  373. t.$set(t.listIndex[index], 'itemIndex', itemIndex);
  374. t.$set(t.listIndex[index], 'wz', itemIndex * t.itemHeight);
  375. t.chulisdata();
  376. }
  377. index++;
  378. await tests();
  379. }
  380. }
  381. await tests()
  382. }
  383. }
  384. }else if(typeindex === 'object'){
  385. if (dNum === 1) {
  386. let valueStr = sjd[0];
  387. if(typeof valueStr[t.rangKey] ==='undefined' || typeof valueStr !=='object' || typeof valueStr ==='undefined' || valueStr ==null){
  388. return;
  389. }
  390. let itemIndex = this.listData[0].findIndex(item=>{
  391. return (item[t.rangKey] == valueStr[t.rangKey])||(parseInt(item[t.rangKeyId]) == parseInt(valueStr[t.rangKeyId]));;
  392. })
  393. if(itemIndex>-1){
  394. this.$set(this.listIndex[0], 'itemIndex', itemIndex);
  395. this.$set(t.listIndex[0], 'wz', itemIndex * t.itemHeight);
  396. }
  397. return
  398. }else if(dNum>1){
  399. let index = 0;
  400. async function tests() {
  401. if(index > dNum) return;
  402. if(typeof t.listIndex[index] === 'object' && typeof t.listIndex[index] !=='undefined'){
  403. let valueStr = t.defaultValue[index];
  404. if(typeof valueStr[t.rangKey] ==='undefined' || typeof valueStr !=='object' || typeof valueStr ==='undefined' || valueStr ==null){
  405. return;
  406. }
  407. let itemIndex = t.listData[index].findIndex(item=>{
  408. return (item[t.rangKey] == valueStr[t.rangKey])||(parseInt(item[t.rangKeyId]) == parseInt(valueStr[t.rangKeyId]));
  409. })
  410. if(itemIndex>-1){
  411. await uni.$tm.sleep(30)
  412. t.$set(t.listIndex[index], 'itemIndex', itemIndex);
  413. t.$set(t.listIndex[index], 'wz', itemIndex * t.itemHeight);
  414. t.chulisdata();
  415. }
  416. index++;
  417. await tests();
  418. }
  419. }
  420. await tests()
  421. }
  422. }
  423. },
  424. scroll(e, index) {
  425. this.scrollEvent = e;
  426. this.childrenIndex = index;
  427. },
  428. scrllEnd(e) {
  429. this.isTounch = false;
  430. if (!this.scrollEvent) return;
  431. let dNum = this.gridNum;
  432. let d;
  433. let t = this;
  434. let idb = 88;
  435. let srcllTop = this.scrollEvent.detail.scrollTop;
  436. if(srcllTop<=0){
  437. srcllTop = 0;
  438. }else if(srcllTop >= this.scrollEvent.detail.srcollHeigh){
  439. srcllTop = this.scrollEvent.detail.srcollHeigh;
  440. }
  441. d = Math.ceil((srcllTop - (this.itemHeight / 2)) / this.itemHeight);
  442. if(d>= t.listData[t.childrenIndex].length-1){
  443. d = t.listData[t.childrenIndex].length-1
  444. }
  445. this.$set(this.listIndex[this.childrenIndex], 'wz', srcllTop)
  446. let isNo = false;//是否相同(和上一次对比。)
  447. if(this.listIndex[this.childrenIndex].itemIndex == d){
  448. isNo = true;
  449. }
  450. if(!this.disabled){
  451. this.$set(this.listIndex[this.childrenIndex], 'itemIndex', d)
  452. }
  453. clearTimeout(idb)
  454. idb = setTimeout(function() {
  455. if(t.disabled){
  456. t.$tm.toast("已禁用")
  457. t.$set(t.listIndex[t.childrenIndex], 'wz', t.listIndex[t.childrenIndex].itemIndex * t.itemHeight)
  458. return;
  459. }else{
  460. t.$set(t.listIndex[t.childrenIndex], 'wz', d * t.itemHeight)
  461. }
  462. if(isNo) return;
  463. for(let i=0;i<t.listIndex.length;i++){
  464. if(i>t.childrenIndex && i < dNum){
  465. t.$set(t.listIndex[i],'itemIndex',0)
  466. t.$set(t.listIndex[i],'wz',0)
  467. }
  468. }
  469. t.chulisdata();
  470. }, 10);
  471. }
  472. },
  473. }
  474. </script>
  475. <style lang="scss" scoped>
  476. .tm-pickersView {
  477. .tm-pickersView-wk {
  478. position: relative;
  479. .tm-pickersView-showbg {
  480. position: absolute;
  481. left: 0;
  482. height: 0;
  483. z-index: 5;
  484. .tm-pickersView-item {
  485. .tm-pickersView-item-text {
  486. text {
  487. transition: all 0.5s;
  488. }
  489. &.textLevel_1 {
  490. text {
  491. font-size: 28upx !important;
  492. }
  493. }
  494. &.textLevel_2 {
  495. text {
  496. font-size: 26upx !important;
  497. }
  498. }
  499. }
  500. }
  501. }
  502. .tm-pickersView-fg {
  503. position: relative;
  504. z-index: 3;
  505. }
  506. }
  507. }
  508. </style>