简体   繁体   中英

Get component ref from Vue @click event

Hopefully a simple one to answer, but I cannot get an HTML reference to the component that triggers an @click event in vue after much searching. So I have a custom component in a list

<ion-list lines="none" v-for="item in uiPosts" :key="item.createdAt">
  <ion-item v-if="!item.skipped" class="ion-no-padding">
   <SummaryCard class="summary" 
                :post=item 
                @click="handleCardClick"
                ... blah blah blah

and a simple handler

const handleCardClick = async (e : Event) => {
   ... stuff
  console.log(e.target); // something like the card title but not the actual card
}

And e.target just gives me granular sub elements for the card like the heading or subheading. Same if I attach @click event to the ion-item in the list. I just want a ref to the thing I actually attach the click event to so I can make sure it is fully scrolled into view when clicked.

Based on the comment from @Duannx, the actual simple answer is just to use event.currentTarget . Then in typescript. . .

const handleCardClick = async (e: Event) => {
  const el = e.currentTarget as HTMLDivElement
  el.scrollIntoView({ behavior: "smooth", block: "start"});
}

Some more janky ways below just if you stumble upon this question. . .

Ok. So from the vue 3 docs (with the composition API switch toggled.!!).

Callback like this:

const cardRefs = ref<HTMLDivElement[]>([])

const handleCardClick = async (idx: number) => {
  const el = cardRefs.value[idx];
  el.scrollIntoView({ behavior: "smooth", block: "end"});
}

Template like this:

     <ion-list lines="none">
        <div v-for="(item, idx) in uiPosts" :key="item.createdAt" ref="cardRefs" @click.capture="handleCardClick(idx)">
          <ion-item v-if="!item.skipped" class="ion-no-padding" >
            <SummaryCard class="summary" 
            :post=item 
            ...

Which solves the challenge in the original question

EDIT:

There is a better way. . because from the docs "It should be noted that the ref array does not guarantee the same order as the source array.". . and this definitely gets weird when you have something like an infinite list.

Instead of passing the callback from the infinite list, derive it from the event. This is more robust

const handleCardClick = async (e: Event) => {     
    const idx = cardRefs.value.findIndex((element)=>{return element.contains(e.target as HTMLElement)})                 
    cardRefs.value[idx].scrollIntoView({ behavior: "smooth", block: "start"});
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM