as-tree-select.vue 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. <template>
  2. <view class="as-select-container" :class="{'as-select-disabled': disabled, 'as-select-border': border}">
  3. <view class="as-select-input" @tap="open">
  4. <input :name="name" :value="label" :placeholder="placeholder" :placeholderStyle="placeholderStyle" disabled/>
  5. <slot name="suffix-icon">
  6. <uni-icons type="bottom" size="18" color="#999"></uni-icons>
  7. </slot>
  8. </view>
  9. <as-popup ref="popup" type="bottom">
  10. <view class="as-tree-select-popup">
  11. <view class="as-tree-select-popup-mask" @tap="close"></view>
  12. <view class="as-tree-select-popup-content">
  13. <as-nav-bar :color="titleColor" :backgroundColor="titleBackgroundColor" :border="false" :statusBar="false"
  14. :title="title" class="as-select-nav-bar">
  15. <template slot="right">
  16. <uni-icons class="rightIcon" :color="titleColor" type="closeempty"
  17. size="23" @click="close"></uni-icons>
  18. </template>
  19. </as-nav-bar>
  20. <scroll-view scroll-y="true" :style="{'height': listHeight}">
  21. <view class="as-list" v-if="options && options.length">
  22. <as-select-item
  23. v-for="item in options"
  24. :key="item[valueKey]"
  25. :data="item"
  26. :labelKey="labelKey"
  27. :valueKey="valueKey"
  28. :checkStrictly="checkStrictly"
  29. :disabled="item.disabled"
  30. @onSelect="confirm">
  31. </as-select-item>
  32. </view>
  33. <as-empty v-else text="暂无数据"></as-empty>
  34. </scroll-view>
  35. </view>
  36. </view>
  37. </as-popup>
  38. </view>
  39. </template>
  40. <script>
  41. import AsSelectItem from './as-select-item.vue';
  42. export default {
  43. name: "as-tree-select",
  44. model: {
  45. prop: 'value',
  46. event: 'input'
  47. },
  48. // options: {
  49. // styleIsolation: 'shared'
  50. // },
  51. components: {
  52. AsSelectItem
  53. },
  54. props: {
  55. name: {
  56. type: String,
  57. require: true
  58. },
  59. disabled: {
  60. type: Boolean,
  61. default: false
  62. },
  63. // 是否可以选择任意一级
  64. checkStrictly: {
  65. type: Boolean,
  66. default: false
  67. },
  68. value: {
  69. type: String,
  70. default: ''
  71. },
  72. listHeight: {
  73. type: String,
  74. default: '258px'
  75. },
  76. placeholder: {
  77. type: String
  78. },
  79. options: {
  80. type: Array,
  81. default: function() {
  82. return []
  83. }
  84. },
  85. valueKey: {
  86. type: String,
  87. default: 'value'
  88. },
  89. labelKey: {
  90. type: String,
  91. default: 'label'
  92. },
  93. // 标题
  94. title: {
  95. type: String,
  96. default: ''
  97. },
  98. // 标题栏文字颜色
  99. titleColor: {
  100. type: String,
  101. default: '#3a3a3a'
  102. },
  103. // 标题栏背景色
  104. titleBackgroundColor: {
  105. type: String,
  106. default: '#fff'
  107. },
  108. // 是否显示边框
  109. border: {
  110. Type: Boolean,
  111. default: true
  112. },
  113. // placeholder的样式(内联样式,字符串),如"color: #ddd"
  114. placeholderStyle: {
  115. Type: String
  116. }
  117. },
  118. data() {
  119. return {
  120. }
  121. },
  122. computed:{
  123. label: function(){
  124. const getParent = (data, nodeId) => {
  125. let arrRes = [];
  126. if (data.length === 0) {
  127. return arrRes;
  128. }
  129. const rev = (options, nodeId) => {
  130. for (let i = 0, length = options.length; i < length; i++) {
  131. const node = options[i];
  132. if (node[this.valueKey] === nodeId) {
  133. arrRes.unshift(node[this.labelKey]);
  134. rev(data, node.parentId);
  135. break;
  136. } else {
  137. if (node.children) {
  138. rev(node.children, nodeId);
  139. }
  140. }
  141. }
  142. return arrRes;
  143. }
  144. arrRes = rev(data, nodeId);
  145. return arrRes;
  146. }
  147. const label = getParent(this.options, this.value);
  148. return label.join('/');
  149. }
  150. },
  151. methods: {
  152. open() {
  153. if(!this.disabled){
  154. this.$refs.popup.open();
  155. }
  156. },
  157. close(){
  158. this.$refs.popup.close();
  159. },
  160. confirm(val){
  161. this.$emit('change', val);
  162. this.$emit('input', val);
  163. this.close();
  164. }
  165. }
  166. }
  167. </script>
  168. <style lang="scss">
  169. .as-select-container {
  170. width: 100%;
  171. border-radius: 4px;
  172. box-sizing: border-box;
  173. .as-select-input{
  174. display: flex;
  175. align-items: center;
  176. min-height: 36px;
  177. position: relative;
  178. gap: 16rpx;
  179. /deep/ .uni-input-input{
  180. pointer-events: none;
  181. }
  182. }
  183. input {
  184. width: 100%;
  185. height: 1.4em;
  186. min-height: 1.4em;
  187. line-height: 1;
  188. font-size: 14px;
  189. color: rgb(51, 51, 51);
  190. }
  191. uni-icons {
  192. flex-shrink: 0;
  193. }
  194. &.as-select-disabled{
  195. background-color: #eee;
  196. }
  197. &.as-select-border{
  198. border: 1px solid #e5e5e5;
  199. padding: 0 10px;
  200. }
  201. }
  202. .as-tree-select-popup {
  203. height: calc(100vh - 50px);
  204. position: relative;
  205. .as-tree-select-popup-mask{
  206. position: absolute;
  207. width: 100%;
  208. height: 100%;
  209. top: 0;
  210. }
  211. .as-tree-select-popup-content{
  212. background: #fff;
  213. // display: flex;
  214. flex-direction: column;
  215. position: absolute;
  216. bottom: 0;
  217. width: 100%;
  218. }
  219. }
  220. .as-select-nav-bar{
  221. border-bottom:1px solid #e5e5e5;
  222. display: block;
  223. }
  224. .as-list{
  225. text-align: left;
  226. }
  227. .as-empty{
  228. height: 258px;
  229. }
  230. </style>