1.实列图片

image.png

2.代码部分

  1. <template>
  2. <div class="ami-input-ip">
  3. <ul class="ipAdress" :class="[actived]" @mouseover="changeColor()">
  4. <li v-for="(item,index) in ipAddress" :key="index">
  5. <ami-input class="ipInputClass"
  6. ref="ipInput"
  7. type="text"
  8. :size="size"
  9. v-model="item.value"
  10. v-bind="$attrs"
  11. :disabled="disabled"
  12. :readonly="readonly"
  13. @input="checkIpVal(item)"
  14. @keyup="turnIpPosition(item,index,$event)"
  15. />
  16. <div class="ip-box"></div>
  17. </li>
  18. </ul>
  19. <div class="icon" v-if="this.clearable&&this.readonly!==true">
  20. <i class="ami-icon-circle-close" @click="clear()"></i>
  21. </div>
  22. </div>
  23. </template>
  24. <script>
  25. export default {
  26. name: 'AmiInputIp',
  27. props: {
  28. size: {
  29. type: String,
  30. default: 'large'
  31. },
  32. // 侦听的值
  33. value: {
  34. type: String,
  35. default: ''
  36. },
  37. // 设置返回值类型
  38. formatStyle: {
  39. type: String,
  40. default: 'node'
  41. },
  42. // 禁用
  43. disabled: {
  44. type: Boolean,
  45. default: false
  46. },
  47. // 是否只读
  48. readonly: {
  49. type: Boolean,
  50. default: false
  51. }
  52. },
  53. data() {
  54. return {
  55. actived: '',
  56. clearable: false,
  57. ipAddress: [{value: ''}, {value: ''}, {value: ''}, {value: ''}]
  58. };
  59. },
  60. mounted() {
  61. if (this.value && this.value.length > 0 && this.value.split('.').length === 4) {
  62. var arr = this.value.split('.');
  63. for (var i in arr) {
  64. this.ipAddress[i].value = arr[i];
  65. }
  66. }
  67. },
  68. watch: {
  69. // 双向数据绑定的value
  70. ipAddress: {
  71. handler(newVal, oldVal) {
  72. let str = '';
  73. for (const i in this.ipAddress) {
  74. if (this.formatStyle === 'noNode') {
  75. str += this.formatter(this.ipAddress[i].value);
  76. } else {
  77. if (str.length > 0) {
  78. str += '.';
  79. }
  80. str += this.ipAddress[i].value === '' ? '000' : this.ipAddress[i].value;
  81. }
  82. }
  83. if (str === '000000000000' || str === '000.000.000.000') {
  84. str = '';
  85. }
  86. // 判断输入框是有值
  87. this.clearable = str.length > 0;
  88. this.$emit('input', str);
  89. },
  90. deep: true
  91. }
  92. },
  93. methods: {
  94. // 清空
  95. clear() {
  96. for (var i in this.ipAddress) {
  97. this.ipAddress[i].value = '';
  98. }
  99. },
  100. // 格式化补零
  101. formatter(val) {
  102. let value = val.toString();
  103. if (value.length === 2) {
  104. value = '0' + value;
  105. } else if (value.length === 1) {
  106. value = '00' + value;
  107. } else if (value.length === 0) {
  108. value = '000';
  109. }
  110. return value;
  111. },
  112. // 检查ip输入是否为0-255
  113. checkIpVal(item) {
  114. // 确保每个值都处于0-255
  115. var val = item.value;
  116. // 处理非数字
  117. val = val.toString().replace(/[^0-9]/g, '');
  118. val = parseInt(val, 10);
  119. if (isNaN(val)) {
  120. val = '';
  121. } else {
  122. val = val < 0 ? 0 : val;
  123. val = val > 255 ? 255 : val;
  124. }
  125. item.value = val;
  126. },
  127. // 光标位置判断
  128. turnIpPosition(item, index, event) {
  129. let self = this;
  130. let e = event || window.event;
  131. if (e.keyCode === 37) {
  132. // 左箭头向左跳转,左一不做任何措施
  133. if (index !== 0 && e.currentTarget.selectionStart === 0) {
  134. self.$refs.ipInput[index - 1].focus();
  135. }
  136. } else if (e.keyCode === 39) {
  137. // 右箭头向右跳转,右一不做任何措施
  138. if (index !== 3 && e.currentTarget.selectionStart === item.value.toString().length) {
  139. self.$refs.ipInput[index + 1].focus();
  140. }
  141. } else if (e.keyCode === 8) {
  142. // 删除键把当前数据删除完毕后会跳转到前一个input,左一不做任何处理
  143. if (index !== 0 && item.value === '') {
  144. self.$refs.ipInput[index - 1].focus();
  145. }
  146. } else if (e.keyCode === 13 || e.keyCode === 32 || e.keyCode === 190) {
  147. // 回车键、空格键、冒号均向右跳转,右一不做任何措施
  148. if (index !== 3) {
  149. self.$refs.ipInput[index + 1].focus();
  150. }
  151. } else if (item.value.toString().length === 3) {
  152. // 满3位,光标自动向下一个文本框
  153. if (index !== 3) {
  154. self.$refs.ipInput[index + 1].focus();
  155. }
  156. }
  157. },
  158. // 鼠标移入事件
  159. changeColor() {
  160. // 判断是否禁用(是否为已读),来显示边框
  161. if (this.disabled === false && this.readonly !== true) {
  162. this.actived = this.actived === 'actived' ? '' : 'actived';
  163. } else {
  164. this.actived = '';
  165. }
  166. }
  167. }
  168. };
  169. </script>
  170. <style>
  171. .ami-input-ip{
  172. position: relative;
  173. width: 100%;
  174. .ipAdress{
  175. display: flex;
  176. border: 1px solid #dcdfe6;
  177. border-radius: 9px;
  178. padding-inline-start: 0px;
  179. //transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
  180. li{
  181. position: relative;
  182. list-style-type: none;
  183. //表格样式
  184. .ipInputClass{
  185. .ami-input__inner{
  186. border: 0;
  187. width: 100%;
  188. padding: 0 10px;
  189. text-align: center;
  190. background: transparent;
  191. }
  192. }
  193. .ip-box{
  194. position: absolute;
  195. bottom: 8px;
  196. right: 0;
  197. border-radius: 50%;
  198. background: #505050;
  199. width: 2px;
  200. height: 2px;
  201. }
  202. }
  203. // 第三个点隐藏
  204. :last-child .ip-box{
  205. display: none;
  206. }
  207. }
  208. // 图标清空
  209. .icon{
  210. position:absolute;
  211. right: 3px;
  212. top:30%;
  213. font-size: 14px;
  214. }
  215. .actived{
  216. border: 1px solid $--input-focus-border;
  217. transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
  218. }
  219. }
  220. </style>

3.说明文档

InputIp ip输入框

通过键盘输入ipv4地址。
无法输入英文,数字大于255的自动转换

基础用法

image.png
v-model通过v-model来绑定数据
:::demo v-model通过v-model来绑定数据

  1. <div style="width: 240px;">
  2. <ami-input-ip v-model="inputIp"></ami-input-ip>
  3. </div>
  4. <script>
  5. export default {
  6. data(){
  7. return{
  8. inputIp:"192.168.1.3"
  9. }
  10. }
  11. }
  12. </script>

:::

禁用状态

image.png
通过 disabled 属性指定是否禁用 ami-input-ip 组件
:::demo 通过 disabled 属性指定是否禁用 ami-input-ip 组件

  1. <div style="width: 240px;">
  2. <ami-input-ip v-model="inputIp" disabled></ami-input-ip>
  3. </div>
  4. <script>
  5. export default {
  6. data(){
  7. return{
  8. inputIp:""
  9. }
  10. }
  11. }
  12. </script>

:::

只读

image.png
使用readonly属性即可得到一个只读的输入框
:::demo 使用readonly属性即可得到一个只读的输入框

  1. <div style="width: 240px;">
  2. <ami-input-ip v-model="inputIp" readonly></ami-input-ip>
  3. </div>
  4. <script>
  5. export default {
  6. data(){
  7. return{
  8. inputIp:"192.168.0.1"
  9. }
  10. }
  11. }
  12. </script>

:::

尺寸

image.png
使用size属性即可控制输入框的大小, 支持输入默认和largesmallmini.
:::demo 使用size属性即可控制输入框的大小, 支持输入默认和largesmallmini.

  1. <div style="width: 240px;">
  2. <ami-input-ip v-model="inputIp" size="large"></ami-input-ip>
  3. </div>
  4. <div style="width: 240px;">
  5. <ami-input-ip v-model="inputIp" size="small"></ami-input-ip>
  6. </div>
  7. <div style="width: 240px;">
  8. <ami-input-ip v-model="inputIp" size="mini"></ami-input-ip>
  9. </div>
  10. <script>
  11. export default {
  12. data(){
  13. return{
  14. inputIp:"192.168.0.1"
  15. }
  16. }
  17. }
  18. </script>

:::

返回格式

image.png
使用formatStyle属性即可控制返回值的格式, 支持输入nodenoNode, 默认为node
node 返回格式为xxx.xxx.xxx.xxx, noNode返回格式为xxxxxxxxxxxx此格式不足字符用0填充。
:::demo

  1. <div style="width: 240px">
  2. <ami-input-ip v-model="inputip"></ami-input-ip>
  3. </div>
  4. <span>返回值为:{{inputip}}</span>
  5. <div style="width: 240px;margin-top:20px;">
  6. <ami-input-ip v-model="ipNoNode" :formatStyle="'noNode'"></ami-input-ip>
  7. <span>返回值为:{{ipNoNode}}</span>
  8. </div>
  9. <script>
  10. export default {
  11. data(){
  12. return{
  13. inputip: '',
  14. ipNoNode: ''
  15. }
  16. }
  17. }
  18. </script>

:::

Attributes

参数 说明 类型 可选值 默认值
v-model 双向绑定(绑定数据) String
disabled 禁用(是否禁止编辑) Boolean true / false false
readonly 只读 boolean true / false false
size 输入框尺寸 String large / small / mini
formatStyle 设置返回值类型 String node / noNode node

Input Events

事件说明 说明 回调参数
clear 在点击由 clearable 属性生成的清空按钮时触发(默认选中) ——