# Ссылки на элементы шаблона

Этот раздел использует синтаксис однофайловых компонентов для примеров кода

Подразумевается, что вы уже изучили и разобрались с разделами Введение в 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>
1
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} />
  }
}
1
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>
1
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>
1
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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

Deployed on Netlify.
Последнее обновление: 2021-01-31, 20:49:49 UTC