vue 填空(一个文字一个方格)

  1. 当前题目的数据
    data() {
        return {
          questionName: "举头望__,低头思___头思_",
          blankNameList: [],
          blankList: [], //绑定每一个格子的model,用于处理用户输入的答案
        }
      },

     

  2. 根据标题,处理好格子数,以及每一个方格所在位置,绑定到model,用于页面渲染
    /**
         * 处理数据
         */
        arrayCount(data){
          let newdata = []
          let index = 1;
          let i = 0;
          for(let k in data){
            let {type,content} = data[i];
            let {type:type2} = data[i+1]||{}
            i++;
            //类型相同且内容相同
            if(type===type2 && content === "_"){
              index++;
            }else{
              newdata.push({
                ...data[k],
                hasCol:index
              })
              index = 1;
            }
          }
          return newdata;
        },
        arrObj(nameList){
          let arrd = [];
          nameList.forEach((item, i) => {
            if (item === '_') {
              arrd.push({
                type: 'input',
                content: "_",
              })
            } else {
              arrd.push({
                type: 'txt',
                content: item,
              })
            }
          })
          return arrd
        },
        /* 处理填空题标题 */
        handleBlankTile(questionName) {
          const nameList = questionName.split('');
          let arrd = this.arrObj(nameList);
          console.log(arrd)
          let arrList = this.arrayCount(arrd);
          let idx = 1;
          let blankList = [];
          arrList.forEach((item)=>{
            if (item.type === "input") {
              let data = [];
              for (let i = 0; i < item.hasCol; i++) {
                data.push({index: idx++})
                blankList.push("")
              }
              item.content = data
            }
          })
          this.blankNameList = arrList;
          this.blankList = blankList;
        },
    

    得到的数据格式( blankNameList, blankList )

  3. 根据以上处理好的数据来渲染html代码
    <div class="title bank-title">
          <template v-for="(subItem, subIdx) in blankNameList">
            <template v-if="subItem.type === 'input'" id="id_inpt">
              <input v-for="(itemIpt, iptIdx) in subItem.content"
                     type="text"
                     :class="['unit-cell-input', 'inputVal']"
                     ref="ids_ipt"
                     v-model="blankList[itemIpt.index - 1]"
                     @input="inputChange($event, itemIpt.index)"
                     @click="changeIdx"
                     @keyup.delete="KeyDelete"
              />
            </template>
            <span v-else>{{subItem.content}}</span>
          </template>
        </div>

     

  4. 判断用户是要输入还是删除,分以下几种情况
    a.单文字输入直接将焦点转移到下一个输入框
    b.删除将焦点转移到上一个输入框
    c.多文字输入填充
    1.拿到用户当前输入框所有文字集合数组
    2.定位是从第几个框开始输入,
    3.输入的文字字数和当前框到最后一个框的输入框数量的关系,是否超出等
    4.将焦点放到最后一个文字所在的输入框
    5.将文字赋值到blankList,更新视图 (不然有bug)
    6.储存用户输入的答案
    /* 填空题输入效果——输入框自动失焦以及转移到下个焦点 */
        inputChange(e, iptI) {
          this.$nextTick(() => {
            const els = this.$refs.ids_ipt;
            switch (e.inputType) {
              case 'insertText':
              case 'insertFromPaste':
                const str = els[iptI - 1].value
                const strList = str.split('')
                const strL = strList.length
                const elsL = els.length
                // alert(strL)
                if (strL > 1) {
                  strList.map((item, i) => {
                    if (i < elsL - iptI + 1) {
                      els[iptI - 1 + i].value = item
                      this.$set(this.blankList, iptI - 1 + i, item)
                    }
                    if (i === strL - 1) {
                      // 字数等于或大于空格数时焦点到最后一个空格
                      if (strL > elsL - iptI || strL === elsL - iptI) {
                        els[elsL - 1].focus()
                      } else {
                        els[iptI + i].focus()
                      }
                    }
                  })
                } else {
                  if (str !== els.length) {
                    if (iptI === this.blankList.length) {
                      els[iptI-1].focus()
                    } else {
                      els[iptI].focus()
                    }
                  }
                }
                break
              case 'deleteContentBackward':
                if (iptI > 1) {
                  els[iptI - 2].focus()
                }
                break
            }
    
            // this.getUserKey(this.currentIdx - 1) //保存用户答案
          })
        },
       /**
         * 根据ref获取相对应下标焦点,将焦点移动最后面
         */
        changeIdx () {
          let findIndex = this.blankList.findIndex(item => !item)
          if (findIndex === -1) {
            findIndex = this.blankList.length - 1;
          }
          this.$nextTick(function(){
            this.$refs.ids_ipt[findIndex].focus()
            let t = this.$refs.ids_ipt[findIndex].value;
            this.$refs.ids_ipt[findIndex].selectionStart = this.$refs.ids_ipt[findIndex].selectionEnd = t.length;
          })
        },
    /**
    * 监听删除事件
    */
    KeyDelete (){
    let findIndex = this.blankList.findIndex(item => !item)
    if (findIndex === -1) {
    findIndex = this.blankList.length - 1;
    }
    this.$nextTick(function(){
    if (findIndex>0) {
    this.$refs.ids_ipt[findIndex-1].focus()
    let t = this.$refs.ids_ipt[findIndex-1].value;
    this.$refs.ids_ipt[findIndex-1].selectionStart = this.$refs.ids_ipt[findIndex-1].selectionEnd = t.length;
    } else {
    this.$refs.ids_ipt[findIndex].focus()
    let t = this.$refs.ids_ipt[findIndex].value;
    this.$refs.ids_ipt[findIndex].selectionStart = this.$refs.ids_ipt[findIndex].selectionEnd = t.length;
    }
    })
    },
     

     

  5. .bank-title {
      margin-bottom: 40px;
      display: flex;
      flex-wrap: wrap;
      input {
        width: 15px;
        height: 21px;
        display: inline-block;
        text-align: center;
        border: 1px solid transparent;
      }
      .unit-cell-input {
        width: 21px;
        height: 21px;
        background: #dedee2;
        margin: 0 4px;
        font-weight: bold;
        color: transparent;
        text-shadow: 0 0 0 #5050de;
        &:focus {
          border: 1px solid #5656df;
        }
      }
    }

     

  6.  

     

  7.  

    参考: https://blog.csdn.net/alisa_lisa/article/details/111823217 

posted @ 2021-12-28 11:41  新上小菜鸟  阅读(516)  评论(0编辑  收藏  举报