index.vue 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. <template>
  2. <uni-shadow-root class="vant-dist-cascader-index"><view v-if="showHeader" class="van-cascader__header">
  3. <text class="van-cascader__title"><slot name="title"></slot>{{ title }}</text>
  4. <van-icon v-if="closeable" :name="closeIcon" class="van-cascader__close-icon" @click.native="onClose"></van-icon>
  5. </view>
  6. <van-tabs :active="activeTab" custom-class="van-cascader__tabs" wrap-class="van-cascader__tabs-wrap" tab-class="van-cascader__tab" :color="activeColor" :border="false" :swipeable="swipeable" @click="onClickTab">
  7. <van-tab v-for="(tab,tabIndex) in (tabs)" :key="tab.tabIndex" :title="tab.selected ? tab.selected[textKey] : placeholder" style="width: 100%;" :title-style="(!tab.selected ? 'color: #969799;font-weight:normal;' : '')">
  8. <view class="van-cascader__options">
  9. <view v-for="(option,index) in (tab.options)" :key="option.index" :class="(option.className)+' '+(utils.optionClass(tab, valueKey, option))" :style="utils.optionStyle({ tab, valueKey, option, activeColor })" :data-option="option" :data-tab-index="tabIndex" @click="onSelect">
  10. <text>{{ option[textKey] }}</text>
  11. <van-icon v-if="utils.isSelected(tab, valueKey, option)" name="success" size="18"></van-icon>
  12. </view>
  13. </view>
  14. </van-tab>
  15. </van-tabs></uni-shadow-root>
  16. </template>
  17. <wxs src="./index.wxs" module="utils"></wxs>
  18. <script>
  19. import VanIcon from '../icon/index.vue'
  20. import VanTab from '../tab/index.vue'
  21. import VanTabs from '../tabs/index.vue'
  22. global['__wxVueOptions'] = {components:{'van-icon': VanIcon,'van-tab': VanTab,'van-tabs': VanTabs}}
  23. global['__wxRoute'] = 'vant/dist/cascader/index'
  24. import { VantComponent } from '../common/component';
  25. var FieldName;
  26. (function (FieldName) {
  27. FieldName["TEXT"] = "text";
  28. FieldName["VALUE"] = "value";
  29. FieldName["CHILDREN"] = "children";
  30. })(FieldName || (FieldName = {}));
  31. const defaultFieldNames = {
  32. text: FieldName.TEXT,
  33. value: FieldName.VALUE,
  34. children: FieldName.CHILDREN,
  35. };
  36. VantComponent({
  37. props: {
  38. title: String,
  39. value: {
  40. type: String,
  41. },
  42. placeholder: {
  43. type: String,
  44. value: '请选择',
  45. },
  46. activeColor: {
  47. type: String,
  48. value: '#1989fa',
  49. },
  50. options: {
  51. type: Array,
  52. value: [],
  53. },
  54. swipeable: {
  55. type: Boolean,
  56. value: false,
  57. },
  58. closeable: {
  59. type: Boolean,
  60. value: true,
  61. },
  62. showHeader: {
  63. type: Boolean,
  64. value: true,
  65. },
  66. closeIcon: {
  67. type: String,
  68. value: 'cross',
  69. },
  70. fieldNames: {
  71. type: Object,
  72. value: defaultFieldNames,
  73. observer: 'updateFieldNames',
  74. },
  75. },
  76. data: {
  77. tabs: [],
  78. activeTab: 0,
  79. textKey: FieldName.TEXT,
  80. valueKey: FieldName.VALUE,
  81. childrenKey: FieldName.CHILDREN,
  82. innerValue: '',
  83. },
  84. watch: {
  85. options() {
  86. this.updateTabs();
  87. },
  88. value(newVal) {
  89. this.updateValue(newVal);
  90. },
  91. },
  92. created() {
  93. this.updateTabs();
  94. },
  95. methods: {
  96. updateValue(val) {
  97. if (val !== undefined) {
  98. const values = this.data.tabs.map((tab) => tab.selected && tab.selected[this.data.valueKey]);
  99. if (values.indexOf(val) > -1) {
  100. return;
  101. }
  102. }
  103. this.innerValue = val;
  104. this.updateTabs();
  105. },
  106. updateFieldNames() {
  107. const { text = 'text', value = 'value', children = 'children', } = this.data.fieldNames || defaultFieldNames;
  108. this.setData({
  109. textKey: text,
  110. valueKey: value,
  111. childrenKey: children,
  112. });
  113. },
  114. getSelectedOptionsByValue(options, value) {
  115. for (let i = 0; i < options.length; i++) {
  116. const option = options[i];
  117. if (option[this.data.valueKey] === value) {
  118. return [option];
  119. }
  120. if (option[this.data.childrenKey]) {
  121. const selectedOptions = this.getSelectedOptionsByValue(option[this.data.childrenKey], value);
  122. if (selectedOptions) {
  123. return [option, ...selectedOptions];
  124. }
  125. }
  126. }
  127. },
  128. updateTabs() {
  129. const { options } = this.data;
  130. const { innerValue } = this;
  131. if (!options.length) {
  132. return;
  133. }
  134. if (innerValue !== undefined) {
  135. const selectedOptions = this.getSelectedOptionsByValue(options, innerValue);
  136. if (selectedOptions) {
  137. let optionsCursor = options;
  138. const tabs = selectedOptions.map((option) => {
  139. const tab = {
  140. options: optionsCursor,
  141. selected: option,
  142. };
  143. const next = optionsCursor.find((item) => item[this.data.valueKey] === option[this.data.valueKey]);
  144. if (next) {
  145. optionsCursor = next[this.data.childrenKey];
  146. }
  147. return tab;
  148. });
  149. if (optionsCursor) {
  150. tabs.push({
  151. options: optionsCursor,
  152. selected: null,
  153. });
  154. }
  155. this.setData({
  156. tabs,
  157. });
  158. wx.nextTick(() => {
  159. this.setData({
  160. activeTab: tabs.length - 1,
  161. });
  162. });
  163. return;
  164. }
  165. }
  166. this.setData({
  167. tabs: [
  168. {
  169. options,
  170. selected: null,
  171. },
  172. ],
  173. });
  174. },
  175. onClose() {
  176. this.$emit('close');
  177. },
  178. onClickTab(e) {
  179. const { index: tabIndex, title } = e.detail;
  180. this.$emit('click-tab', { title, tabIndex });
  181. this.setData({
  182. activeTab: tabIndex,
  183. });
  184. },
  185. // 选中
  186. onSelect(e) {
  187. const { option, tabIndex } = e.currentTarget.dataset;
  188. if (option && option.disabled) {
  189. return;
  190. }
  191. const { valueKey, childrenKey } = this.data;
  192. let { tabs } = this.data;
  193. tabs[tabIndex].selected = option;
  194. if (tabs.length > tabIndex + 1) {
  195. tabs = tabs.slice(0, tabIndex + 1);
  196. }
  197. if (option[childrenKey]) {
  198. const nextTab = {
  199. options: option[childrenKey],
  200. selected: null,
  201. };
  202. if (tabs[tabIndex + 1]) {
  203. tabs[tabIndex + 1] = nextTab;
  204. }
  205. else {
  206. tabs.push(nextTab);
  207. }
  208. wx.nextTick(() => {
  209. this.setData({
  210. activeTab: tabIndex + 1,
  211. });
  212. });
  213. }
  214. this.setData({
  215. tabs,
  216. });
  217. const selectedOptions = tabs.map((tab) => tab.selected).filter(Boolean);
  218. const value = option[valueKey];
  219. const params = {
  220. value,
  221. tabIndex,
  222. selectedOptions,
  223. };
  224. this.innerValue = value;
  225. this.$emit('change', params);
  226. if (!option[childrenKey]) {
  227. this.$emit('finish', params);
  228. }
  229. },
  230. },
  231. });
  232. export default global['__wxComponents']['vant/dist/cascader/index']
  233. </script>
  234. <style platform="mp-weixin">
  235. @import '../common/index.css';.van-cascader__header{align-items:center;display:flex;height:48px;justify-content:space-between;padding:0 16px}.van-cascader__title{font-size:16px;font-weight:600;line-height:20px}.van-cascader__close-icon{color:#c8c9cc;font-size:22px;height:22px}.van-cascader__tabs-wrap{height:48px!important;padding:0 8px}.van-cascader__tab{color:#323233!important;flex:none!important;font-weight:600!important;padding:0 8px!important}.van-cascader__tab--unselected{color:#969799!important;font-weight:400!important}.van-cascader__option{align-items:center;cursor:pointer;display:flex;font-size:14px;justify-content:space-between;line-height:20px;padding:10px 16px}.van-cascader__option:active{background-color:#f2f3f5}.van-cascader__option--selected{color:#1989fa;font-weight:600}.van-cascader__option--disabled{color:#c8c9cc;cursor:not-allowed}.van-cascader__option--disabled:active{background-color:initial}.van-cascader__options{-webkit-overflow-scrolling:touch;box-sizing:border-box;height:384px;overflow-y:auto;padding-top:6px}
  236. </style>