tm-pickersView.vue 14 KB

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