# Ссылки на элементы шаблона
В этом разделе используется синтаксис однофайловых компонентов в примерах кода
Подразумевается, что уже изучили и разобрались с разделами Введение в 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, поэтому ссылки на элементы шаблона будут доступны только после первоначальной отрисовки.
Ссылки, используемые как ссылки на элементы шаблона, ведут себя точно также, как и любые другие ref-ссылки: они реактивны и могут быть переданы в функции композиции (или возвращены из них).
# Использование с 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
- См. также: Вычисляемые свойства и методы наблюдатели