Location>code7788 >text

Vue 3.5's useTemplateRef makes ref manipulation of the DOM even silkier!

Popularity:293 ℃/2024-09-04 14:28:13

preamble

To access the DOM and subcomponents in vue3 you can use a ref for template references, but there are some confusing things about this ref. For example, is the defined ref variable a responsive data or a DOM element? Also the value of the ref attribute in the template is clearly a string, such asref="inputEl"Why does it have the same name as in the script?inputElWhat about variables tied to one piece? That's why Vue 3.5 introduced auseTemplateReffunction that solves these problems perfectly.

Follow the public number: [Front-end Ouyang], give yourself a chance to advance vue

Problems with ref template references

Let's take a look at one.reactThe example of using ref to access a DOM element in the code is as follows:

const inputEl = useRef<HTMLInputElement>(null);
<input type="text" ref={inputEl} />

utilizationuseReffunction defines a function namedinputElvariable, then set the value of the ref attribute of the input element to the value of theinputElvariable, so that it is possible to pass theinputElThe variable accesses the input field.

inputElBecause it's a.currentattribute of the object, since theinputElvariable is assigned to the ref attribute, so his.currentattribute is updated to the value of the input DOM element, which is very programmatically intuitive.

Let's go over it again.vue3in it would be very unprogramming intuitive by comparison.

I wonder how many students like Ouyang, the first contact with vue3 is always in the template likereactSame as binding a ref variable to the ref attribute instead of the name of the ref variable. For example, code like the following:

<input type="text" :ref="inputEl" />

const inputEl = ref<HTMLInputElement>();

What's even worse is that writing it this way doesn't report errors !!!!When we use theinputElvariable to access the input box will always get theundefined

After much troubleshooting it turns out that the ref property receives not a ref variable, but the name of the ref variable. The correct code would look like this:

<input type="text" ref="inputEl" />

const inputEl = ref<HTMLInputElement>();

There is also the fact that if we draw the logic related to the ref template references into hooks, then we have to define the ref variable corresponding to the ref attribute in the vue component as well.

The hooks code is as follows:

export default function useRef() {
  const inputEl = ref<HTMLInputElement>();
  function setInputValue() {
    if () {
       = "Hello, world!";
    }
  }

  return {
    inputEl,
    setInputValue,
  };
}

In the hooks, it defines a file namedinputRefvariables, and in thesetInputValuefunction will be passed theinputRefvariable operates on the input field.

The vue component code is as follows:

<template>
  <input type="text" ref="inputEl" />
  <button @click="setInputValue">do sth (for sb)inputassign a value to something</button>
</template>

<script setup lang="ts">
import useInput from "./useInput";
const { setInputValue, inputEl } = useInput();
</script>

While we won't be using theinputElvariable, but it still needs to be imported from the hooksuseInputVariables. Doesn't everyone think this is strange? Importing a variable and not explicitly using that variable.

If you don't go ahead and import from hooks here, theinputElvariable, then theinputElYou can't bind an input box to a variable.

useTemplateRef function

To solve the problem of ref template references described above, in Vue 3.5 a newuseTemplateReffunction.

useTemplateRefThe usage of the function is simple: it takes only one argumentkey, is a string. The return value is a ref variable.

where the value of the parameter key string should be equal to the value of the ref attribute in the template.

The return value is a ref variable whose value points to the DOM element or subcomponent referenced by the template.

Let's look at an example where the previous demo is changed touseTemplateRefThe code after the function is as follows:

<template>
  <input type="text" ref="inputRef" />
  <button @click="setInputValue">do sth (for sb)inputassign a value to something</button>
</template>

<script setup lang="ts">
import { useTemplateRef } from "vue";

const inputEl = useTemplateRef<HTMLInputElement>("inputRef");
function setInputValue() {
  if () {
     = "Hello, world!";
  }
}
</script>

The value of the ref attribute in the template is a string"inputRef"

Use in scriptsuseTemplateReffunction, the first parameter passed in is also the string"inputRef"useTemplateRefThe return value of the function is the ref variable pointing to the input field.

due toinputElis a ref variable, so to access the DOM element input in the click event you need to use the

Here we are stuffing the input box with the string "Hello, world!", so we use the = "Hello, world!"

UseduseTemplateReffunction is much more programmatically intuitive than it was before. the value of the ref attribute in template is a string"inputRef"UseuseTemplateReffunction also passes in the string"inputRef"You'll be able to get the corresponding template reference.

Use of useTemplateRef in hooks

Going back to the hooks example we talked about earlier, using theuseTemplateRefThe post-hooks code is as follows:

export default function useInput(key) {
  const inputEl = useTemplateRef<HTMLInputElement>(key);
  function setInputValue() {
    if () {
       = "Hello, world!";
    }
  }
  return {
    setInputValue,
  };
}

Now we don't need to export variables in the hooksinputElis used, because this variable is only needed inside hooks.

The vue component code is as follows:

<template>
  <input type="text" ref="inputRef" />
  <button @click="setInputValue">do sth (for sb)inputassign a value to something</button>
</template>

<script setup lang="ts">
import useInput from "./useInput";
const { setInputValue } = useInput("inputRef");
</script>

Since we don't need to use theinputElvariable, so there's no need to start with theuseInputvariable introduced ininputElup. And before not using theuseTemplateRefprogram we would have to introduce theinputElVariables up.

Dynamically switching ref-bound variables

There are times when we need to dynamically switch the variables referenced by the ref template according to different scenarios, in which case the value of the ref attribute in the template is dynamic, rather than a written string. In this scenariouseTemplateRefIt is also supported with the following code:

<template>
  <input type="text" :ref="refKey" />
  <button @click="switchRef">switch modes or data streamsrefBound variables</button>
  <button @click="setInputValue">do sth (for sb)inputassign a value to something</button>
</template>

<script setup lang="ts">
import { useTemplateRef, ref } from "vue";

const refKey = ref("inputEl1");
const inputEl1 = useTemplateRef<HTMLInputElement>("inputEl1");
const inputEl2 = useTemplateRef<HTMLInputElement>("inputEl2");
function switchRef() {
   = === "inputEl1" ? "inputEl2" : "inputEl1";
}
function setInputValue() {
  const curEl = === "inputEl1" ? inputEl1 : inputEl2;
  if () {
     = "Hello, world!";
  }
}
</script>

In this scenario the ref binding in the template is a variable.refKeyThe program can be accessed by clicking on theSwitching ref-bound variablesThe buttons can be toggledrefKeyvalue of the input box. Correspondingly, the variables bound to the input input box are removed from theinputEl1The variable is switched toinputEl2Variables.

useTemplateRefHow was it achieved?

Let's see.useTemplateRefThe source code is actually quite simple, and the simplified code is as follows:

function useTemplateRef(key) {
  const i = getCurrentInstance();
  const r = shallowRef(null);
  if (i) {
    const refs =  === EMPTY_OBJ ? ( = {}) : ;
    (refs, key, {
      enumerable: true,
      get: () => ,
      set: (val) => ( = val),
    });
  }
  return r;
}

first usinggetCurrentInstancemethod gets the current vue instance object and assigns it to the variablei

then callshallowReffunction generates a shallow ref object with an initial value of null. the ref object is theuseTemplateRefThe ref object returned by the function.

The next step is to determine the current vue instance and if it exists, read the instance'srefsproperty object, if the instance object does not have arefsproperty, then initialize an empty object to the vue instance object'srefsProperties.

vue instance object above thisrefsIf you've used vue2, you should be familiar with the attribute object, which holds all the DOM elements and component instances that have the ref attribute registered.

vue3, although unlike vue2, does not incorporate therefsattribute object is open to the developer, but his internals still use the vue instance'srefsattribute object to store instances of elements and components registered with the ref attribute in the template.

Here themethodologyrefsAttribute objects are intercepted, and the intercepted field is the variablekeyvalue, and thiskeyvalue is the value bound in the template using theref attribute.

Taking our demo above as an example, the code in the template is as follows:

<input type="text" ref="inputRef" />

Here, the ref attribute is used to add the ref attribute to the vue instance'srefsproperty object with an input input box registered on top of it.value is pointing to the input field of the DOM element.

Then in the script it is used like thisuseTemplateRefThe:

const inputEl = useTemplateRef<HTMLInputElement>("inputRef")

call (programming)useTemplateReffunction is passed in as a string"inputRef"inuseTemplateRefFunctions internally use themethodologyrefsAttribute objects are intercepted, and the intercepted fields are variableskeyvalue, which is the value of the call touseTemplateRefThe string passed in by the function"inputRef"

When initialized, vue handles the input input box above theref="inputRef"It would then execute code like the one below:

refs[ref] = value

at this timevalueis the value that points to the input field of the DOM element.refis the value of the string"inputRef"

Then this line of code is assigning the DOM element input input box to therefsobject above theinputRefAttributes on.

Since there is a great deal of interest here in therefsobject above theinputRefattribute for write operations, so it will go to theuseTemplateRefin a functiondefinedsetIntercept. The code is as follows:

const r = shallowRef(null);

(refs, key, {
  enumerable: true,
  get: () => ,
  set: (val) => ( = val),
});

existsetThe intercept assigns the DOM element input to the ref variable.rAnd thisrjust likeuseTemplateRefThe ref variable returned by the function.

The same is true when the objectrefstargetinputRefattribute for read operations will also go here in thegetIn the intercept, returnuseTemplateRefThe ref variable defined in the functionrThe value of the

summarize

New in Vue 3.5, theuseTemplateReffunction solves several problems in the ref attribute:

  • It is not programming intuitive that the value of the ref attribute in template is the value of the corresponding ref variable in scriptvariable name

  • It is not possible to visualize whether a ref variable is responsive data or a DOM element in script without using ts?

  • After pumping the logic related to defining and accessing DOM elements into hooks, the variables that hold the DOM elements must also be imported from the hooks in the component, even though they will not be used in the vue component.

Then we talked aboutuseTemplateReffunction implementation. In theuseTemplateReffunction will define a ref object in theuseTemplateRefThe last thing the function does is return the ref object.

follow withFor vue instances above therefsproperty object for get and set interception.

Initialization, which handles the ref attribute in the template, will have an effect on the vue instance above therefsattribute object for write operations.

It will then be intercepted by set, where it will set theuseTemplateRefThe value of the ref object defined in the function is assigned to the bound DOM element or component instance.

(indicates contrast)useTemplateReffunction is to return this ref object, so we can pass theuseTemplateRefThe return value of the function gets the DOM element or component instance bound to the ref attribute in the template.

Follow the public number: [Front-end Ouyang], give yourself a chance to advance vue

Also Ouyang wrote an open source ebookvue3 Compilation Principles Revealed, reading this book can give you a qualitative improvement in your knowledge of vue compilation. This book is accessible to beginner and intermediate front-ends and is completely free, just asking for a STAR.