# Ссылки на элементы шаблона
Этот раздел использует синтаксис однофайловых компонентов для примеров кода
Подразумевается, что вы уже изучили и разобрались с разделами Введение в Composition API и Основы реактивности. Если нет — прочитайте их сначала.
При использовании Composition API, концепции реактивных ссылок и ссылок на элементы шаблона унифицированы. Для того, чтобы получить ссылку на элемент в шаблоне или экземпляр компонента, необходимо объявить ссылку ref как обычно и вернуть её из setup():
<template>
<div ref="root">Это корневой элемент</div>
</template>
<script>
import { ref, onMounted } from 'vue'
export default {
setup() {
const root = ref(null)
onMounted(() => {
// элемент DOM будет определён в ref после первоначальной отрисовки
console.log(root.value) // <div>Это корневой элемент</div>
})
return {
root
}
}
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
В данном примере предоставляется доступ к root
в контексте отрисовки и выполняется его привязка к блоку в качестве его ссылки через ref="root"
. В алгоритме обновления виртуального DOM, если ключ ref
у VNode соответствует ссылке в контексте отрисовки, то соответствующему элементу или компоненту VNode будет присвоено значение этой ссылки. Это выполняется в процессе монтирования / обновления виртуального DOM, поэтому ссылки на элементы шаблона будут определяться только после первоначальной отрисовки.
Ссылки, используемые как ссылки на элементы шаблона, ведут себя точно также, как и любые другие ссылки: они реактивны и могут быть переданы в функции композиции (или возвращены из них).
# Использование с JSX
export default {
setup() {
const root = ref(null)
return () =>
h('div', {
ref: root
})
// с использованием JSX
return () => <div ref={root} />
}
}
2
3
4
5
6
7
8
9
10
11
12
13
# Использование внутри v-for
Ссылки на элементы шаблона в Composition API не имеют специальной обработки при использовании внутри v-for
. Вместо этого следует использовать функции для выполнения пользовательской обработки:
<template>
<div v-for="(item, i) in list" :ref="el => { if (el) divs[i] = el }">
{{ item }}
</div>
</template>
<script>
import { ref, reactive, onBeforeUpdate } from 'vue'
export default {
setup() {
const list = reactive([1, 2, 3])
const divs = ref([])
// убедитесь, что сбрасываете ссылки перед каждым обновлением
onBeforeUpdate(() => {
divs.value = []
})
return {
list,
divs
}
}
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# Отслеживание ссылок на элементы шаблона
Отслеживание изменений ссылок на элементы шаблона может быть альтернативой использованию хуков жизненного цикла, как было показано в предыдущем примере.
Главное отличие от хуков жизненного цикла в том, что эффекты watch()
и watchEffect()
запускаются перед монтированием или обновлением DOM, поэтому ссылка на элемент шаблона не будет обновлена, когда наблюдатель запускает эффект:
<template>
<div ref="root">Это корневой элемент</div>
</template>
<script>
import { ref, watchEffect } from 'vue'
export default {
setup() {
const root = ref(null)
watchEffect(() => {
// Этот эффект будет запущен перед обновлением DOM и, соответственно,
// ссылка на элемент шаблона ещё не будет содержать ссылки на элемент.
console.log(root.value) // => null
})
return {
root
}
}
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Поэтому методы наблюдателей, которые используют ссылки на элементы шаблона должны определяться с опцией flush: 'post'
. Это позволит запускать эффект после обновления DOM и убедиться, что ссылки на элементы шаблона останутся синхронизированными с DOM и ссылаются на правильный элемент.
<template>
<div ref="root">Это корневой элемент</div>
</template>
<script>
import { ref, watchEffect } from 'vue'
export default {
setup() {
const root = ref(null)
watchEffect(() => {
console.log(root.value) // => <div></div>
},
{
flush: 'post'
})
return {
root
}
}
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
- См. также: Вычисляемые свойства и методы наблюдатели