Как в родителе получить $refs элемента ребенка компонента?

Всем привет. Во vue новичок.
Есть компонент с-input

<template>
  <div>
    <input type="text" class="input__field"
        :value="value"
        @focus="onFocus"
        @input="onChange($event.target.value)"
        @blur="onBlur" />
    <span class="input__placeholder" :class="classPlaceholder">
      <slot></slot>
    </span>
  </div>
</template>

<script>
export default {
  name: "CInput",
  props: {
    value: {
      type: [String, Number],
      required: true
    },
  },
  data() {
    return {
      classPlaceholder: null
    }
  },
  created() {
    if (this.value.trim()) {
      this.classPlaceholder = "input__placeholder--hidden"
    }
  },
  methods: {
    onFocus() {
      if (!this.value) {
        this.classPlaceholder = "input__placeholder--opacity"
      }
    },
    onChange(val) {
      this.$emit('value', val)
      if (val) {
        this.classPlaceholder = "input__placeholder--hidden"
      } else {
        this.classPlaceholder = "input__placeholder--opacity"
      }
    },
    onBlur() {
      if (this.value.trim()) {
        this.classPlaceholder = "input__placeholder--hidden"
      } else {
        this.$emit('value', this.value.trim())
        this.classPlaceholder = ""
      }
    }
  }
}
</script>


Так же есть компонент item

<template>
  <div>
    <div class="complex-item__content"
        @keydown.esc="close">
      <div class="complex-item__left">
        <div class="priority complex-item__priority">
          <span class="priority__icon"
              :class="content.priority.iconClass"></span>
        </div>
      </div>
      <div class="complex-item__center">
        <div class="complex-item__header">
          <span v-show="!editTitle"
              class="complex-item__title"
              @dblclick="showEditTitle(content.key)">{{ content.title }}</span>
          <c-input v-show="editTitle"
              class="input complex-item__edit-title"
              ref="input"
              :value="edit.title"
              @value="edit.title = $event"
              @keydown.ctrl.enter="endEdit(content.key, edit.title, null)">Укажите название задачи</c-input>
        </div>
        <div class="complex-item__body">
          <p v-show="!editText"
              class="complex-item__text"
              @dblclick="showEditText = true"
              style="white-space: pre-line">{{ content.text }}</p>
           <c-textarea v-show="editText"
               class="textarea complex-item__edit-text"
               :value="edit.text"
               @value="edit.text = $event"
               @keydown.ctrl.enter="endEdit(content.key, null, edit.text)">Укажите описание задачи</c-textarea>
        </div>
      </div>
      <div class="complex-item__right">
                <span class="btn complex-item__remove"
                    @click="removeTodo(content.key)">
                  <span class="btn__text">Удалить</span>
                </span>
        <span class="complex-item__date-add">{{ content.date }}</span>
      </div>
    </div>
  </div>
</template>

<script>
import CInput from "@/components/CInput";
import CTextarea from "@/components/CTextarea";

export default {
  name: "Item",
  components: {
    CInput,
    CTextarea
  },
  props: {
    content: {
      type: Object,
      required: true
    },
    removeTodo: {
      type: Function,
      required: true
    },
    editTitleTodo: {
      type: Function,
      required: true
    },
    editTextTodo: {
      type: Function,
      required: true
    },
  },
  data() {
    return {
      edit: {
        title: this.content.title,
        text: this.content.text
      },
      editTitle: false,
      editText: false
    }
  },
  methods: {
    close() {
      this.editTitle = false
      this.editText = false
    },
    showEditTitle(id) {
      this.editTitle = true
      this.$nextTick(() => {
        this.$refs.input.$el.childNodes[0].focus()
      })
    },
    endEdit(id, title, text) {
      if (title) {
        this.editTitleTodo(id, title)
        this.editTitle = false
      }
      if (text) {
        this.editTextTodo(id, text)
        this.editText = false
      }
    },
  }
}
</script>



Как при двойном клике по complex-item__title в компоненте item, вызвать событие фокус у <input/> компоненты с-input?
Если в компоненте item при вызове компоненты c-input присвоить как сейчас ref="input", то что бы вызывать событие фокуса у <input/> внутри компоненты с-input у меня получилось только так
this.$nextTick(() => {
        this.$refs.input.$el.childNodes[0].focus()
      })

Мне кажется что это говнокод, имеется ли во вью более правильное решение ?
Так же вопрос на счет метода close() (что бы скрыть компоненту c-input и c-textarea), почему он срабатывает только тогда, когда c-input или c-textarea получают фокус, как можно сделать что бы не зависимо от фокуса этих полей, срабатывал этот метод при нажатии на esc ?
Заранее спасибо.
  • Вопрос задан
  • 175 просмотров
Пригласить эксперта
Ответы на вопрос 2
Fragster
@Fragster
помогло? отметь решением!
Реализовать у c-input метод focus() и вызывать его из "родителя": this.$refs.input.focus()
Ответ написан
Комментировать
@Egor1324 Автор вопроса
Правильно ли будет, если я сделаю вот так:
Компонента c-input

<template>
  <div>
    <input type="text" class="input__field"
        :value="value"
        :ref="'input'"
        @input="onChange($event.target.value)"/>
  </div>
</template>

export default {
  name: "CInput",
  props: {
    value: {
      type: [String, Number],
      required: true
    },
  },
  mounted() {
    this.$emit("ref", this.$refs.input)
  },
  methods: {
    onChange(val) {
      this.$emit('value', val)
    },
  }
}


Компонента item

<template>
  <div>
    <div class="complex-item__content" @keydown.esc="close">
      <span v-show="!editTitle"
          class="complex-item__title"
          @dblclick="showEditTitle">{{ content.title }}</span>
          <c-input v-show="editTitle"
              class="input complex-item__edit-title"
              @ref="input = $event"
              :value="edit.title"
              @value="edit.title = $event"
              @keydown.ctrl.enter="endEdit(content.key, edit.title, null)" />
    </div>
  </div>
</template>

import CInput from "@/components/CInput";

export default {
  name: "Item",
  components: {
    CInput
  },
  props: {
    content: {
      type: Object,
      required: true
    },
    editTitleTodo: {
      type: Function,
      required: true
    },
  },
  data() {
    return {
      edit: {
        title: this.content.title,
      },
      editTitle: false,
    }
  },
  methods: {
    close() {
      this.editTitle = false
    },
    showEditTitle() {
      this.editTitle = true
      this.$nextTick(() => {
        this.input.focus()
      })
    },
    endEdit(id, title) {
      this.editTitleTodo(id, title)
      this.editTitle = false
    },
  }
}

Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы