E
E
Egor Astreiko2020-08-28 15:32:43
Vue.js
Egor Astreiko, 2020-08-28 15:32:43

How to get the $refs of a component's child element in the parent?

Hello. New to vue.

There is a c-input component

<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>


There is also an item component

<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>



How to double-click on an itemcomplex-item__title component to trigger a focus event on the c-input component ? If in the item component, when calling the component , assign as now<input/>
c-inputref="input"<input/>
this.$nextTick(() => {
        this.$refs.input.$el.childNodes[0].focus()
      })

It seems to me that this is a govnokod, is there a more correct solution in view?
Also, the question is about the method close()(to hide the component c-input и c-textarea), why does it only work when c-input или c-textareathey receive focus, how can I make this method work when esc is pressed regardless of the focus of these fields?
Thanks in advance.

Answer the question

In order to leave comments, you need to log in

2 answer(s)
A
Anton Anton, 2020-08-28
@Fragster

Implement the focus() method on c-input and call it from the "parent": this.$refs.input.focus()

E
Egor Astreiko, 2020-08-28
@Egor1324

Is it correct if I do this:

c-input component

<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 component

<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
    },
  }
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question