资讯详情

vue3输入框生成的时候自动获取焦点

vue生成输入框时,自动获取焦点

前言

当我们在做vue3在项目中,在修改一些信息时,需要双击或点击按钮来操作,使数据变成输入框来修改数据,当输入框失去焦点时保存,但不方便,输入框无法获得焦点,导致用户体验差。

创建示例演示(创建文件,可以忽略)

首先,我们需要一个vue3如何创建一个项目?vue3的项目,新建一个空的文件夹,cmd打开,输入

1. vue create 项目的名称 举例:vue create demo 我们选择自定义,即 2. Manually select features 回车,按需介绍自己需要的,按空间选择 3. 举例: >(*) Babel  (*) TypeScript  ( ) Progressive Web App (PWA) Support  (*) Router  (*) Vuex  (*) CSS Pre-processors  (*) Linter / Formatter  ( ) Unit Testing  ( ) E2E Testing 回车 4. 选择用于启动项目的选择 Vue.js选择版本(使用箭头键)3.x 5. 类型组件语法的使用? 输入N 6. 将 Babel 与 TypeScript 一起使用(现代模式和自动检测) polyfills、转译 JSX 需要)?输入Y 7. 路由器使用history模式?选择N (这决定了你编译的地址是否包含 /#/ 的字样) 8. 选择一个 CSS 预处理器 根据我自己的需要,我选择在这里Sass/SCSS (with dart-sass) 9. 选择一个 linter /格式化程序配置 选择ESLint   Standard config 10. Pick additional lint features 选择Lint on save 11. 您更喜欢将 Babel、ESLint 等配置在哪里? 选择In dedicated config files,这样好处理 12. 将此保存为未来项目的预设?我选择在这里N,看个人需求 

我们用来定义一些简单的页面bootstrap有些一些款式public文件夹的index.html介绍外部风格<link href=“https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.min.css” rel=“stylesheet”>书写在title标签下,在HomeView页面文件书写简单的代码

<template>   <div class="container">     <ul class="list-group">
      <template v-for="(i, index) in list" :key="index">
        <li class="list-group-item d-flex justify-content-between" v-if="!i.checked">
          <div class="form-group form-check mb-0">
            <input type="checkbox" class="form-check-input" />
            <label v-if="!i.isEdit" class="form-check-label" @dblclick="showEdit(i, index)"> {
    
       { i.name }} </label>
            <label v-else class="form-check-label" :for="'i-' + index">
              <!-- -->
              <input type="text" v-model="editValue" @blur="changeEdit" ref="myInput" /></label>
          </div>
          <button type="button" class="close" aria-label="Close" @click="remove(index)">
            <span aria-hidden="true">&times;</span>
          </button>
        </li>
      </template>
    </ul>
  </div>
</template>

JS代码如下

<script lang="ts">
import { 
         defineComponent, reactive, toRefs, ref } from 'vue'

export default defineComponent({ 
        
  name: 'HomeView',
  setup() { 
        
    // 元素节点
    const myInput = ref(null)
    // 编辑的索引
    let editIndex = 0
    // 是否获取焦点
    const open = 0
    // 数据
    const state = reactive({ 
        
      value: '',
      editValue: '',
      list: [
        { 
        
          name: '1',
          checked: false,
          isEdit: false
        },
        { 
        
          name: '2',
          checked: false,
          isEdit: false
        },
        { 
        
          name: '3',
          checked: false,
          isEdit: false
        }
      ]
    })
    // 双击修改
    const showEdit = (item, index) => { 
        
      if (open == 0) { 
        
        open = 1
        editIndex = index
        item.isEdit = true
        state.editValue = item.name
      }
    }
    // 失去焦点
    const changeEdit = () => { 
        
      state.list[editIndex] = { 
        
        name: state.editValue,
        checked: false,
        isEdit: false
      }
      open = 0
      editIndex = 0
    }
    // 移除
    const remove = (index) => { 
        
      state.list.splice(index, 1)
    }

    return { 
        
      ...toRefs(state),
      showEdit,
      changeEdit,
      remove,
      myInput
    }
  }
})
</script>

基础页面搭建好了之后,在终端输入

npm run serve

将项目跑起来,我们会看到三条任务

双击就可以编辑,点击叉号可以删除,复选框和添加的未加上

解决方法

当我们双击进行编辑的时候,会发现输入框不能获取焦点,用户的输入十分不方便,而且当我们想失去焦点的时候,也不许去点击输入框再失去焦点才能取消修改,十分的麻烦。

1、方法一

我们可以添加异步的手法让输入框出现之后再执行获取焦点的手法来解决,具体的解决代码如下

    // 双击修改
    const showEdit = (item, index) => { 
        
      if (open == 0) { 
        
        setTimeout(() => { 
        
          myInput.value[0].focus()
        })
        open = 1
        editIndex = index
        item.isEdit = true
        state.editValue = item.name
      }
    }

通过插入一个延时器来解决问题

2、方法二

熟悉vue2的朋友应该知道$nextTick就可以解决,但在这里vue3需要配合监听使用,还需要ref来选择我们需要操作的元素对象,查阅官网的ref使用方法,和vue2不一样,在vue2中,我们需要给我们需要的元素节点打上ref标签,读取直接使用this.$refs来操作,演示如下

template:
	 <button ref="btn"></button>
methods:
	this.$refs.btn

vue3中的使用读取:

<template>
  <div ref="box">div</div>
</template>

<script>
// 引入
import { 
         onMounted, ref } from 'vue';
export default { 
        
  name: 'App',
  setup() { 
        
    let box = ref(null);
    // onMounted() 中的行为会在声明周期 mounted 中执行。
    onMounted(() => { 
        
    // 在这里就可以读取到我们需要的元素节点
      console.log('box.value', box.value);
    })
    return { 
        box};
  }
}
</script>

但是,我们的input框是根据state.list每一项的isEdit决定的,也就是说onMounted执行的时候,我们的输入框一直是未打开的,只有当我们双击的时候,才会唤醒我们的输入框,而onMounted只会在页面完全加载的时候执行一次,所以当我们双击的时候,控制台就会打印出null,此时我们是获取不到我们需要的元素节点,也就是代码

// 使用之前记得引入onMounted 
onMounted(() => { 
        
   console.log('myInput.value', myInput.value)
})

控制台打印出的是null

这时候获取焦点

onMounted(() => { 
        
   console.log('myInput.value', myInput.value)
    myInput.value[0].focus()
})

控制台就会报错

Uncaught TypeError: Cannot read properties of null (reading '0')
    at Proxy.showEdit (HomeView.vue?4752:47:1)
    at onDblclick (HomeView.vue?475e:67:1)
    at callWithErrorHandling (runtime-core.esm-bundler.js?d2dd:155:1)
    at callWithAsyncErrorHandling (runtime-core.esm-bundler.js?d2dd:164:1)
    at HTMLLabelElement.invoker (runtime-dom.esm-bundler.js?2725:369:1)

如果我们使用onUpdated,通过获取页面更新之后就去让输入框获取焦点

// 使用之前记得引入onUpdated 
onUpdated(() => { 
        
   console.log('myInput.value', myInput.value)
})

我们可以获取一个空数组的代理对象,而且我们失去焦点就会报错

// 代理对象
Proxy { 
        0: input}[[Handler]]: Object
	[[Target]]: Array(0)
	[[IsRevoked]]: false

报错:

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'focus')
    at eval (demoView.vue?0f1f:69:1)
    at callWithErrorHandling (runtime-core.esm-bundler.js?d2dd:155:1)
    at callWithAsyncErrorHandling (runtime-core.esm-bundler.js?d2dd:164:1)
    at Array.hook.__weh.hook.__weh (runtime-core.esm-bundler.js?d2dd:2685:1)
    at flushPostFlushCbs (runtime-core.esm-bundler.js?d2dd:356:1)
    at flushJobs (runtime-core.esm-bundler.js?d2dd:401:1)

我们需要监视open的变化,在使用nextTick当页面完全加载的时候获取输入框的元素节点在使其获取焦点接口,因为我们之前是使用let open = 0,我们需要一定的修改,否则watchopen会报错:

No overload matches this call.
  The last overload gave the following error.
    Argument of type 'number' is not assignable to parameter of type 'object'.

引入:

import { 
         defineComponent, reactive, toRefs, ref, nextTick, watch } from 'vue'

修改open

    // 是否获取焦点
    let open = ref(0)

将后面所用到的所有open改成open.value,添加监听代码:

    watch(open, (newValue, oldValue) => { 
        
      if (newValue == 1) { 
        
        nextTick(() => { 
        
          console.log(myInput.value)
          console.log('--- DOM更新了 ---')
          myInput.value[0].focus()
        })
      }
    })

这时候我们就可以在每次双击改变open,即代码:open.value = 1,就会被监听到,从而使输入框获取焦点。

标签: weh快速连接器tvr60

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台