「评论有奖」老板给我提了一个变态需求,我咬着牙把它给完成了!__JavaScript__Vue.js__前端
发布于 3 年前 作者 banyungong 1155 次浏览 来自 分享
粉丝福利 : 关注VUE中文社区公众号,回复视频领取粉丝福利

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

本文已参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金。

前言

昨天老板忽然来到我的工位前,给我提了一个表单需求:

这个表单要新增一个"规则"字段,后台会给你一个默认内容,你把这个内容默认放到输入框里边,要求是用户只能修改在小括号内的内容,其他的内容是不可修改的 我一听头都懵了,咋还有这种需求呀!! 心中千万只马儿奔腾而过~ 但是没法呀,老板给钱,咱就得干活嘛。稍微思考了一下,认为其实这个需求的功能应该还是可以实现的. 于是就开始干起来吧!

思路

一般输入框是可以自由的输入文字的,那么怎么限制输入框输入文字呢? 我们需要在el-input设置value属性,value只跟随绑定的数据的变化而变化,而绑定的数据的变化在输入事件里边去处理. 这里我们就需要抛弃以前使用v-model的方式去更新值的变化. 代码如下:

<el-input
  size="small"
  on-input={v => {
    item.__onChange && item.__onChange(v, form[item.__key], { form, key: item.__key })
  }}
  ref = { item.__key }
  props={{
    value: form[item.__key],
    placeholder: '输入内容信息',
    ...item
  }}
></el-input>

那么需要在__onChange里边写什么规则才能让用户只能在内容里边的小括号里边输入内容,其他内容只保持可读的状态呢?既然是其他内容是只读的内容,小括号里的内容是可写的内容,那么思路来了,我们可以把小括号里变化的内容给删除掉,然后在输入的时候,我们去比对一下删掉小括号内容以后的所有内容是否是和之前的内容删除小括号的内容相等,如果相等的话,那么证明用户输入的内容是在小括号里边输入的,则把数据更新成用户输入的数据。否则不更新.

规则开发

那么思路有了,我们开干吧!

  this.formArr =  new createForm()
  .createInput({
    __key: 'rule',
    label: '规则',
    type: 'textarea',
    __notAutoInput: true,
    __defaultVal: '今日信息: 娱乐新闻(XX)条, 体育新闻(XX)条',
    __onChange:  (inputVal, val, { form, key }) => {
      // inputVal 用户输入的内容
      // val 目前页面显示的内容(输入之前的内容)
      let reg = /\([\w\W]*?\)|([\w\W]*?)/g // 兼容中英文两种括号
      let input = inputVal.replace(reg, '') // 去掉现在在输入的内容括号里边的空格
      let value = val && val.replace(reg, '') // 去掉括号里边原来的内容的空格
      if (input === value) { // 比对去掉空格内容后,是否一致,如果是一致的话,则说明没有修改空格以外的内容,则让用户修改
        form[key] = inputVal // 数据更新成用户输入的内容
      }
    }
  }).form

GIF.gif 好了,我们的功能基本就完成了。 哈哈。 于是我屁颠屁颠去把功能提交了,给老板看,老板试了一下,默默的说: "你这基本功能是实现了,但是总体体验不是太好呀,我在小括号以外的地方输入的时候,老会跳到文字的最后面去了,你再去把这里优化优化吧!", 我…(此处省略一千次), 发泄完心情,日子还是得往下过呀。 那么还是找找资料看看有没有解决的方法吧.

优化api介绍

终于在谷歌的帮助下,找到可以实现这个优化的一个api

setSelectionRange

HTMLInputElement.setSelectionRange 方法用于设定<input> 或 <textarea> 元素中当前选中文本的起始和结束位置 他们再结合各自底下的api可以实现焦点跳转到指定内容的位置上。有了可以使用的api后,我们马上写一个Demo试试看:

<body>
    <textarea id="txtUserID" oninput="inputHandle()"></textarea>
    <script>
        var textbox = document.getElementById("txtUserID")
        textbox.value = '123456789'
        function setFocus(textbox, index) {
          if (textbox.setSelectionRange) {
            textbox.focus();
            textbox.setSelectionRange(index, index + 3);
          }
        }
        function inputHandle(v) {
          setFocus(textbox, 2)
        }
    </script>
</body>

F5A00B06-BF10-4413-A3CB-9ECA747C87E2.png 使用setSelectionRange方法传递两个参数,起始参数和最后参数如果不一致,则可以实现数据的任意选中,如果起始参数和最后参数是一致的,则可以实现设置焦点到任意位置上.

优化开发

在demo中,我们知道要设置焦点的话,我们需要拿到输入框的dom对象和用户输入的位置,那么如何拿到用户输入的位置呢? 我们可以把页面显示的内容和用户要输入的内容一个字符一个字符的进行对比,直到发现两个字符串对比出不一样的字符的时候,跳出循环,并返回当前的字符串索引。这个索引的位置减一就是用户输入的位置了. 那么我们就写一下比对字符串的功能

// 找到索引
findIndex (newVal, oldVal) {
  let newValArr = newVal.split('')
  let oldValArr = oldVal.split('')
  for (let i = 1; i <= newVal.length; i++) {
    let newItem = newValArr.slice(0, i)
    let oldItem = oldValArr.slice(0, i)
    if (JSON.stringify(newItem) !== JSON.stringify(oldItem)) {
      return i
    }
  }
  return newVal.length
}

然后就是把之前在demo中写的设置焦点的方法拿进来

// 设置焦点
setFocus (textbox, index) {
  if (textbox.createTextRange) {
    var r = textbox.createTextRange();
    r.collapse(true);
    r.moveStart('character', index);
    r.select()
  } else if (textbox.setSelectionRange) {
    textbox.focus();
    textbox.setSelectionRange(index, index);
  }
}

最后我们在之前写的表单里边加上如果用户没有在小括号内输入的时候,比对字符串,并设置焦点的主逻辑了.

this.formArr =  new createForm()
.createInput({
  __key: 'rule',
  label: '规则',
  type: 'textarea',
  __notAutoInput: true,
  __defaultVal: '今日信息: 娱乐新闻(XX)条, 体育新闻(XX)条',
  __onChange:  (inputVal, val, { form, key }) => {
    let reg = /\([\w\W]*?\)|([\w\W]*?)/g // 兼容中英文两种括号
    let input = inputVal.replace(reg, '') // 去掉现在在输入的内容括号里边的空格
    let value = val && val.replace(reg, '') // 去掉括号里边原来的内容的空格
    if (input === value) { // 比对去掉空格内容后,是否一致,如果是一致的话,则说明没有修改空格以外的内容,则让用户修改
      form[key] = inputVal
    } else {
      // 如果用户没有在小括号内输入的时候,比对字符串,并设置焦点的主逻辑
      let index = self.findIndex(inputVal, val)
      let dom = self.$refs.myForm.$el.querySelector(`textarea[aria-label=规则]`)
      if (dom && (index || index === 0)) {
        // 由于
        setTimeout(() => {
          self.setFocus(dom, index - 1)
        }, 10)
      }
    }
  }
}).form

最后的效果:

GIF.gif

写在最后

OK, 那么以上就是我在实际工作中遇到的一个小难题了。 虽然感觉被刁难了一下,虽然找资料费了点时间,但是最后的最后,结果还是可人的。 写完老板满意,自己也感觉学到了些东西。 还是挺开心的。 哈哈哈! 感谢大家看到最后,如果觉得本篇文章对你也有所帮助的话,可以给文章点个赞哟! 那么,我们下次见啦~

版权声明:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 作者: 强风吹拂丶 原文链接:https://juejin.im/post/7024106183153680391

回到顶部