如何在 Vue 3 Composition API 的 v-for 循环中使用模板引用移动焦点?

huangapple go评论54阅读模式
英文:

How do I move focus with template refs in a v-for loop ( Vue 3 Composition API)?

问题

Here is the translated portion of your text:

我正在使用一个按钮来显示/隐藏更多或更少的列表项,并希望在单击按钮时使用 ref 来聚焦于“更多”项中的第一个项(这将是第六个项,或 listItem[5])。在 Vue Options API 中,这相对容易。但是我无法在 Composition API 中使其工作。我在 vue devtools 中看到了组件的所有 ref 列表:

listItem:Array[12] (Ref)
0:<li>
1:<li>
2:<li>
3:<li>
4:<li>
5:<li>
6:<li>
7:<li>
8:<li>
9:<li>
10:<li>
11:<li>

当按钮被点击时,我收到一个错误 Uncaught TypeError: Cannot read properties of undefined (reading 'value')。我对 Composition API 相对较新,几乎感觉像一个进退两难的情况,我想引用某些尚不存在的东西。我在这里缺少什么?

我的代码:

<script setup>
import { ref } from 'vue'

const listItem = ref([])
const showAllCounties = ref(false)

const showhideItems = (index) => {
  if (!showAllCounties.value) {
    return index < 5
  } else {
    return true
  }
}

const showFullList = () => {
  document.activeElement.blur()
  showAllCounties.value = !showAllCounties.value
  if (listItem) {
    console.log('yes') // 返回 'yes'
    console.dir(listItem) // 显示带有所有 12 个项的代理数组
  }

  const target = listItem[5]
  if (target) {
    target.value.focus()
    console.log('yes, ' + target)
  } else {
    console.log('no')
  }

  listItem[5].value.focus()

  // 也尝试过在 onMounted() 中记录 listItem 和 listItem.value[5] 到控制台。
}
</script>

<template>
  <ul>
    <li
      v-for="(county, index) in project.data.counties"
      v-show="showhideItems(index)"
      class="project-counties-list"
      ref="listItem"
      :key="county.id"
    >
      {{ county.county_name }}, {{ index }}
    </li>
  </ul>
  <button type="button" @click="showFullList">{{ ButtonText }}</button>
</template>

请注意,这只是您提供的代码的翻译部分,不包括额外的解释或答案。

英文:

I am using a button to show/hide more or fewer list items, and want to use a ref to focus on the first of the "more" items when the button is clicked (this would be the sixth item, or listItem[5]). In the vue Options API, this is relatively easy. But I cannot get it work with the Composition API. I see all of the refs listed for the component in vue devtools:

listItem:Array[12] (Ref)
0:&lt;li&gt;
1:&lt;li&gt;
2:&lt;li&gt;
3:&lt;li&gt;
4:&lt;li&gt;
5:&lt;li&gt;
6:&lt;li&gt;
7:&lt;li&gt;
8:&lt;li&gt;
9:&lt;li&gt;
10:&lt;li&gt;
11:&lt;li&gt;

When the button gets clicked, I get an error Uncaught TypeError: Cannot read properties of undefined (reading &#39;value&#39;). I am relatively new to the Composition API, and it almost feels like a Catch-22, where I want to reference something that doesn't really exist yet. What am I missing here?

My code

&lt;script setup&gt;
import { ref } from &#39;vue&#39;
const listItem = ref([])
const showAllCounties = ref(false)
const showhideItems = (index) =&gt; {
if (!showAllCounties.value) {
return index &lt; 5
} else {
return true
}
}
const showFullList = () =&gt; {
document.activeElement.blur()
showAllCounties.value = !showAllCounties.value
if (listItem) {
console.log(&#39;yes&#39;) // returns &#39;yes&#39;
console.dir(listItem) // shows proxy array with all 12 items
}
const target = listItem[5]
if (target) {
target.value.focus()
console.log(&#39;yes, &#39; +target)
} else {
console.log(&#39;no&#39;)
}
listItem[5].value.focus()
//also tried listItem.value[5].focus()
}
&lt;/script&gt;
&lt;template&gt;
&lt;ul&gt;
&lt;li
v-for=&quot;(county, index) in project.data.counties&quot;
v-show=&quot;showhideItems(index)&quot;
class=&quot;project-counties-list&quot;
ref=&quot;listItem&quot;
:key=&quot;county.id&quot;
&gt;
{{ county.county_name }}, {{ index }}
&lt;/li&gt;
&lt;/ul&gt;
&lt;button type=&quot;button&quot; @click=&quot;showFullList&quot;&gt;{{ ButtonText }}&lt;/button&gt;
&lt;/template&gt;

I've also tried logging listItem and listItem.value[5] to the console in onMounted().

答案1

得分: 1

这是花了我很长时间才想出来的解决方案。关键之一是要使用 listItem.value[5],而不是 listItem[5].value。希望我已经学会了如何处理 ref 数组。我还需要使用 nextTick() 来移动焦点 - 而且我之前的示例中忘记了包括 tabindex。所以:

<script setup>
import { ref, nextTick, computed } from 'vue'
const listItem = ref([])

let showAllCounties = ref(false)

const showHideItems = (index) => {
  return showAllCounties.value
  ? true
  : index < 5
}

const showHideFullList = () => {
  showAllCounties.value = !showAllCounties.value
  nextTick(() => {
    const target = listItem.value[5]
    if (target) {
      target.focus()
    }
  })
}

const showMoreButtonText = computed(() => {
  return showAllCounties.value
    ? 'Show less'
    : 'Show more'
})
</script>

<template>
<ul>
<li
  v-for="(county, index) in project.data.counties"
  v-show="showHideItems(index)"
  :id="`li-${index}`"
  class="project-counties-list"
  ref="listItem"
  :key="county.id"
  :tabindex="index === 5 ? -1 : false"
>
  {{ county.county_name }}
</li>
</ul>
<button
	type="button"
	class="toggle"
    @click="showHideFullList"
  >{{ showMoreButtonText }}
  </button>
</template>

希望这对你有所帮助。

英文:

Here's the solution that took me forever to figure out. The big key was to use listItem.value[5] instead of not listItem[5].value. Lesson learned (I hope) about how to deal with ref arrays. I also needed nextTick() to get the focus moved -- plus I had forgotten to include the tabindex in my previous example. So:

&lt;script setup&gt;
import { ref, nextTick } from &#39;vue&#39;
const listItem = ref([])
let showAllCounties = ref(false)
const showHideItems = (index) =&gt; {
return showAllCounties.value
? true
: index &lt; 5
}
const showHideFullList = () =&gt; {
showAllCounties.value = !showAllCounties.value
nextTick(() =&gt; {
const target = listItem.value[5]
if (target) {
target.focus()
}
})
}
const showMoreButtonText = computed(() =&gt; {
return showAllCounties.value
? &#39;Show less&#39;
: &#39;Show more&#39;
})
&lt;/script&gt;
&lt;template&gt;
&lt;ul&gt;
&lt;li
v-for=&quot;(county, index) in project.data.counties&quot;
v-show=&quot;showHideItems(index)&quot;
:id=&quot;`li-${index}`&quot;
class=&quot;project-counties-list&quot;
ref=&quot;listItem&quot;
:key=&quot;county.id&quot;
:tabindex=&quot;index === 5 ? -1 : false&quot;
&gt;
{{ county.county_name }}
&lt;/li&gt;
&lt;/ul&gt;
&lt;button
type=&quot;button&quot;
class=&quot;toggle&quot;
@click=&quot;showHideFullList&quot;
&gt;{{ showMoreButtonText }}
&lt;/button&gt;
&lt;/template&gt;

huangapple
  • 本文由 发表于 2023年5月24日 23:35:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/76325225.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定