xm-keyboard-input.vue 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. <template>
  2. <view class="xm-keyboard-input" :style="{
  3. 'justify-content': align
  4. }">
  5. <view v-for="(item, index) in values" :key="index" class="xm-keyboard-input-item"
  6. :class="{
  7. 'xm-cur': cur === index,
  8. 'xm-show-pointer': showPointer,
  9. }" :style="{
  10. marginLeft: (index == 0 ? 0 : (18 - max)) + 'px',
  11. maxWidth: maxSize + 'px',
  12. maxHeight: maxSize + 'px',
  13. }" @click="changeCur(index)">
  14. <xm-square height="120%">
  15. <view class="xm-keyboard-input-cnt" :class="{
  16. 'xm-cursor': cursor && cur === index && !item,
  17. }" :style="{
  18. maxWidth: maxSize + 'px',
  19. maxHeight: maxSize + 'px',
  20. }">
  21. {{ item }}
  22. </view>
  23. </xm-square>
  24. </view>
  25. </view>
  26. </template>
  27. <script>
  28. export default {
  29. name: 'xm-keyboard-input',
  30. emits: ['change'],
  31. props: {
  32. initValue: {
  33. type: String,
  34. default: ''
  35. },
  36. cursor: {
  37. type: Boolean,
  38. default: false,
  39. },
  40. max: {
  41. type: Number,
  42. default: 8,
  43. },
  44. showPointer: {
  45. type: Boolean,
  46. default: true,
  47. },
  48. maxSize: {
  49. type: Number,
  50. default: 40,
  51. },
  52. align: {
  53. type: String,
  54. default: 'center',
  55. // default: 'space-between',
  56. }
  57. },
  58. data() {
  59. return {
  60. cur: 0,
  61. values: []
  62. }
  63. },
  64. methods: {
  65. changeCur(index) {
  66. this.cur = index;
  67. this.toChange();
  68. },
  69. toChange(){
  70. this.$emit('change', this.cur)
  71. },
  72. toAdd(v){
  73. this.values[this.cur] = v;
  74. // #ifdef VUE2
  75. this.$set(this.values, this.cur, v);
  76. // #endif
  77. if(this.cur < this.max - 1){
  78. this.cur ++;
  79. this.toChange()
  80. }
  81. },
  82. toDel(){
  83. // 处理一下, 如果是最后一位 并且有值的情况下, 只移除值不变更位置, 或者主动选择到了某一位置
  84. if(this.cur == (this.max - 1) && this.values[this.cur] || this.values[this.cur]){
  85. this.resetCurValue();
  86. return ;
  87. }
  88. if(this.cur <= 0){
  89. this.cur = 0;
  90. }else{
  91. this.cur --
  92. this.resetCurValue();
  93. this.toChange()
  94. }
  95. },
  96. resetCurValue(){
  97. // #ifdef VUE2
  98. this.$set(this.values, this.cur, '');
  99. // #endif
  100. // #ifdef VUE3
  101. this.values[this.cur] = '';
  102. this.$forceUpdate()
  103. // #endif
  104. this.toChange()
  105. },
  106. toClear(){
  107. this.cur = 0;
  108. this.initValues();
  109. this.toChange()
  110. },
  111. changeValue(v){
  112. let max = Math.max(v.length, this.max);
  113. for (let i = 0; i < max; i++) {
  114. this.values[i] = v.charAt(i);
  115. // #ifdef VUE2
  116. this.$set(this.values, i, v.charAt(i))
  117. // #endif
  118. }
  119. // #ifdef VUE3
  120. this.$forceUpdate()
  121. // #endif
  122. let cur = this.values.findIndex(x => !x)
  123. this.cur = cur === -1 ? this.max - 1 : cur;
  124. this.toChange()
  125. },
  126. initValues(){
  127. let vs = [];
  128. vs.length = this.max;
  129. vs.fill('');
  130. this.values = vs;
  131. }
  132. },
  133. mounted() {
  134. this.initValues();
  135. this.changeValue(this.initValue || '')
  136. }
  137. }
  138. </script>
  139. <style scoped lang="scss">
  140. .xm-keyboard-input {
  141. display: flex;
  142. $theme: #007AFF;
  143. $themeBackground: rgba(0,73,255,0.03);
  144. @keyframes blink {
  145. 0% {
  146. opacity: 0;
  147. }
  148. 50% {
  149. opacity: 1;
  150. }
  151. 100% {
  152. opacity: 0;
  153. }
  154. }
  155. &-item {
  156. width: 100%;
  157. height: 100%;
  158. box-sizing: border-box;
  159. border: 1px solid #CCC;
  160. border-radius: 2px;
  161. &:first-child{
  162. margin-left: 0;
  163. }
  164. &.xm-show-pointer:nth-child(8){
  165. border-style: solid;
  166. }
  167. &.xm-show-pointer:nth-child(2){
  168. position: relative;
  169. margin-right: 5px;
  170. &::after{
  171. content: ' ';
  172. position: absolute;
  173. right: -12px;
  174. top: calc(50% - 3px);
  175. display: flex;
  176. align-items: center;
  177. width: 6px;
  178. height: 6px;
  179. background-color: #CCC;
  180. border-radius: 100%;
  181. }
  182. }
  183. &.xm-show-pointer:nth-child(8){
  184. border-style: dashed;
  185. border-color: #4DC790;
  186. background-color: #E9FAF2;
  187. color: #28CD80;
  188. }
  189. &.xm-cur {
  190. border-color: $theme;
  191. background-color: $themeBackground;
  192. transition: 0.1s;
  193. }
  194. .xm-cursor {
  195. &::after {
  196. color: $theme;
  197. content: '|';
  198. animation: blink 1s infinite;
  199. }
  200. }
  201. }
  202. &-cnt {
  203. display: flex;
  204. align-items: center;
  205. justify-content: center;
  206. width: 100%;
  207. height: 100%;
  208. }
  209. }
  210. </style>