tm-stepper.vue 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. <template>
  2. <view class="tm-stepper d-inline-block">
  3. <view class="flex-center" :style="{ width: `${width}rpx` }">
  4. <view :class="[isJianDisabled||disabled?'opacity-6 gray':'']">
  5. <tm-button @touchcancel="endlongpressEvent" @touchend="endlongpressEvent"
  6. @touchstart="$emit('touchstart', 'minus')" @longpress="longpressEvent('-')" :fllowTheme="fllowTheme"
  7. :disabled="isJianDisabled || disabled ? true : false"
  8. :shadow="isJianDisabled || disabled ? 0 : shadwo_num" :black="black_tmeme" @click="setStep('-')"
  9. :item-class="circular?' pa-0':` round-l-${round} `" icon-size="24" :round="circular?round:0"
  10. :theme="disabled ? '' : color_tmeme" :width="height" :height="height" block icon="icon-minus">
  11. </tm-button>
  12. </view>
  13. <input v-if="fixed!=0" @blur="inputVal" @input="inputVal" :disabled="(disabled||disabledInput)"
  14. v-model="setVal" type="digit" :style="{ height: `${height}rpx`, width: `calc(100% - ${height}rpx)` }"
  15. class="text-align-center text-size-n fulled"
  16. :class="[`text-${font_color}`, black_tmeme&&!circular ? 'grey-darken-4 bk' : '',black_tmeme? 'text-grey-lighten-4' : '',circular?'':'grey-lighten-4']" />
  17. <input v-if="fixed==0" @blur="inputVal" @input="inputVal" :disabled="(disabled||disabledInput)"
  18. v-model="setVal" type="number" :style="{ height: `${height}rpx`, width: `calc(100% - ${height}rpx)` }"
  19. class="text-align-center grey-lighten-4 text-size-n fulled"
  20. :class="[`text-${font_color}`, black_tmeme&&!circular ? 'grey-darken-4 bk' : '',black_tmeme? 'text-grey-lighten-4' : '',circular?'':'grey-lighten-4']" />
  21. <view :class="[isAddDisabled||disabled?'opacity-6 gray':'']">
  22. <tm-button @touchcancel="endlongpressEvent" @touchend="endlongpressEvent"
  23. @touchstart="$emit('touchstart', 'add')" @longpress="longpressEvent('+')" :fllowTheme="fllowTheme"
  24. :shadow="isAddDisabled || disabled ? 0 : shadwo_num" :black="black_tmeme" @click="setStep('+')"
  25. :item-class="circular?' pa-0':` round-r-${round} `" icon-size="24" :round="circular?round:0"
  26. :theme="disabled ? '' : color_tmeme" :disabled="isAddDisabled || disabled ? true : false"
  27. :width="height" :height="height" block icon="icon-plus"></tm-button>
  28. </view>
  29. </view>
  30. </view>
  31. </template>
  32. <script>
  33. /**
  34. * 步进器
  35. * @property {String|Number} value = [] 默认:'',值,推荐使用value.sync或者v-model
  36. * @property {Boolean} disabled = [] 默认:false,是否禁用
  37. * @property {Boolean} black = [] 默认:false,是否暗黑模式。
  38. * @property {Number|String} step = [] 默认:1, 步幅。
  39. * @property {String} color = [] 默认:primary, 主题色。
  40. * @property {String} fontColor = [] 默认:black, 输入框的文字主题色。
  41. * @property {String|Number} round = [] 默认:3, 圆角。
  42. * @property {String|Number} shadow = [] 默认:3, 圆角。
  43. * @property {String|Number} max = [] 默认:999, 最大值。
  44. * @property {String|Number} min = [] 默认:0, 最小值。
  45. * @property {String|Number} width = [] 默认:200, 宽度,单位rpx。
  46. * @property {String|Number} height = [] 默认:70, 高度,单位rpx。
  47. * @property {String} name = [] 默认:'',提交表单时的的字段名称标识
  48. * @property {Boolean|String} disabledInput = [] 默认:false,是否禁用输入框
  49. * @property {Boolean|String} circular = [] 默认:false,按钮四角是否跟随圆角
  50. * @property {Number} fixed = [] 默认:0, 小数点位数
  51. * @example <tm-stepper value="50"></tm-stepper>
  52. */
  53. import tmButton from '@/tm-vuetify/components/tm-button/tm-button.vue';
  54. export default {
  55. components: {
  56. tmButton
  57. },
  58. name: 'tm-stepper',
  59. model: {
  60. prop: 'value',
  61. event: 'input'
  62. },
  63. props: {
  64. value: {
  65. type: Number | String,
  66. default: 0
  67. },
  68. //提交表单时的的字段名称
  69. name: {
  70. type: String,
  71. default: ''
  72. },
  73. disabled: {
  74. type: Boolean,
  75. default: false
  76. },
  77. //禁用输入功能
  78. disabledInput: {
  79. type: Boolean | String,
  80. default: false
  81. },
  82. black: {
  83. type: Boolean | String,
  84. default: null
  85. },
  86. // 步幅,默认1
  87. step: {
  88. type: Number,
  89. default: 1
  90. },
  91. //固定小数点位数,0表示整数
  92. fixed: {
  93. type: Number,
  94. default: NaN
  95. },
  96. color: {
  97. type: String,
  98. default: 'primary'
  99. },
  100. fontColor: {
  101. type: String,
  102. default: 'black'
  103. },
  104. round: {
  105. type: String | Number,
  106. default: 3
  107. },
  108. circular: {
  109. type: Boolean | String,
  110. default: false
  111. },
  112. shadow: {
  113. type: String | Number,
  114. default: 3
  115. },
  116. // 跟随主题色的改变而改变。
  117. fllowTheme: {
  118. type: Boolean | String,
  119. default: true
  120. },
  121. max: {
  122. type: Number | String,
  123. default: 999
  124. },
  125. min: {
  126. type: Number | String,
  127. default: 0
  128. },
  129. height: {
  130. type: Number | String,
  131. default: 60
  132. },
  133. width: {
  134. type: Number | String,
  135. default: 180
  136. },
  137. //回调函数。默认返回true即增减,否则不执行增减。
  138. callback: {
  139. type: Function | Object | Boolean,
  140. default: true
  141. }
  142. },
  143. data() {
  144. return {
  145. setVal: '',
  146. timeid: 598985656
  147. };
  148. },
  149. mounted() {
  150. this.setVal = this.value;
  151. },
  152. watch: {
  153. value: function(val) {
  154. this.jianchData(parseFloat(val));
  155. }
  156. },
  157. computed: {
  158. isJianDisabled() {
  159. if (isNaN(parseInt(this.setVal))) return false;
  160. if (parseInt(this.setVal) <= this.min) return true;
  161. return false;
  162. },
  163. isAddDisabled() {
  164. if (isNaN(parseInt(this.setVal))) return false;
  165. if (parseInt(this.setVal) >= this.max) return true;
  166. return false;
  167. },
  168. black_tmeme: function() {
  169. if (this.black !== null) return this.black;
  170. return this.$tm.vx.state().tmVuetify.black;
  171. },
  172. color_tmeme: function() {
  173. if (this.$tm.vx.state().tmVuetify.color !== null && this.$tm.vx.state().tmVuetify.color && this
  174. .fllowTheme) {
  175. return this.$tm.vx.state().tmVuetify.color;
  176. }
  177. return this.color;
  178. },
  179. font_color: function() {
  180. if (this.fontColor) return this.fontColor;
  181. return this.color;
  182. },
  183. shadwo_num: function() {
  184. if (typeof this.shadow !== 'undefined') return this.shadow;
  185. return 3;
  186. }
  187. },
  188. destroyed() {
  189. clearInterval(this.timeid);
  190. },
  191. methods: {
  192. async setStep(ty) {
  193. if (this.disabled) return;
  194. if (typeof this.callback !== 'boolean' && this.callback !== true) {
  195. uni.showLoading({
  196. title: '...',
  197. mask: true
  198. })
  199. let p = await this.callasync();
  200. uni.hideLoading();
  201. if (p !== true) return;
  202. }
  203. this.$nextTick(function() {
  204. var val = parseFloat(this.value);
  205. if (!isNaN(this.fixed) && this.fixed > 0) {
  206. val = val.toFixed(this.fixed)
  207. if (isNaN(val) || val == 0 || val == '0' || val == '' || !val) {
  208. val = '0.' + this.strWidth(this.fixed) + this.step
  209. }
  210. val = parseFloat(val)
  211. let setval = '0.' + this.strWidth(this.fixed) + this.step
  212. setval = parseFloat(setval);
  213. if (ty == '+') {
  214. val += setval
  215. } else {
  216. val -= setval
  217. }
  218. } else if (!isNaN(this.fixed) && this.fixed == 0) {
  219. val = val.toFixed(this.fixed)
  220. val = parseInt(val)
  221. if (ty == '+') {
  222. val += this.step
  223. } else {
  224. val -= this.step
  225. }
  226. } else if (isNaN(this.fixed)) {
  227. if (ty == '+') {
  228. val += this.step
  229. } else {
  230. val -= this.step
  231. }
  232. }
  233. if (val < 0) {
  234. if (val <= this.min) {
  235. val = this.min;
  236. }
  237. clearInterval(this.timeid);
  238. } else if (val >= this.max) {
  239. val = this.max;
  240. clearInterval(this.timeid);
  241. }
  242. const realVal = val;
  243. this.setVal = isNaN(realVal) ? '' : String(val);
  244. this.$emit('input', this.setVal);
  245. this.$emit('update:value', this.setVal);
  246. this.$emit('change', this.setVal);
  247. });
  248. },
  249. inputVal(e) {
  250. var val = parseFloat(e.detail.value)
  251. this.jianchData(val);
  252. },
  253. strWidth(len) {
  254. let v = '';
  255. for (let i = 0; i < len - 1; i++) {
  256. v += '0';
  257. }
  258. return v;
  259. },
  260. jianchData(val) {
  261. this.$nextTick(function() {
  262. if (!isNaN(this.fixed) && this.fixed > 0) {
  263. val = val.toFixed(this.fixed)
  264. if (isNaN(val) || val == 0 || val == '0' || val == '' || !val) {
  265. val = '0.' + this.strWidth(this.fixed) + this.step
  266. }
  267. } else if (!isNaN(this.fixed) && this.fixed == 0) {
  268. val = val.toFixed(this.fixed)
  269. }
  270. const realval = val;
  271. if (val < this.min) {
  272. val = String(this.min);
  273. }
  274. if (val > this.max) {
  275. val = String(this.max);
  276. }
  277. this.setVal = isNaN(parseFloat(realval)) ? '' : String(val);
  278. this.$emit('input', this.setVal);
  279. this.$emit('update:value', this.setVal);
  280. this.$emit('change', this.setVal);
  281. });
  282. },
  283. longpressEvent(ty) {
  284. if (this.disabled) return;
  285. let t = this;
  286. clearInterval(this.timeid);
  287. this.timeid = setInterval(async function() {
  288. await t.setStep(ty);
  289. }, 250);
  290. },
  291. endlongpressEvent(ty) {
  292. clearInterval(this.timeid);
  293. },
  294. //异步回调
  295. async callasync() {
  296. let verify = this.callback;
  297. verify = await verify()
  298. if (typeof verify === 'function') {
  299. verify = await verify()
  300. }
  301. if (typeof verify !== 'boolean') verify = true;
  302. return verify;
  303. }
  304. }
  305. };
  306. </script>
  307. <style lang="scss"></style>