在实现 Vue-Router 的 VueJS SPA 中实现嵌套的 $refs

Posted

技术标签:

【中文标题】在实现 Vue-Router 的 VueJS SPA 中实现嵌套的 $refs【英文标题】:Implementing nested $refs in a VueJS SPA implementing Vue-Router 【发布时间】:2021-08-05 02:38:27 【问题描述】:

我正在开发一个使用 Vue / Vue-Router 的 Laravel/VueJS SPA。我有一个 Vue 组件,它被分配了一个 $ref (在组件 C / 嵌套子组件内),它封装在主 Vue-Router 组件 (组件 B) 中> 注入到布局中(Component A - Layout Component

我需要访问与此 $ref 对应的此元素(在组件 C 内),但是我无法访问它,因为组件层次结构(在组件 A 内)由组件B中声明的信息构成。

(Layout-Component / $root) - Vue Layout Component: --(Vue-Router-Component) -
Primary component injected into layout via Vue-Router - Child Component of
Component A --(dynamic-form-field) - Child Component of Vue-Router-Component

<Layout-Component ref="componentA">
  <Vue-Router-Component ref="componentB">
    <dynamic-form-field ref="componentC"></dynamic-form-field>
  </Vue-Router-Component>
</Layout-Component>

我尝试使用标准的嵌套 $ref 语法访问$ref

this.$root.$refs['componentB'].$refs['componentC'].attribute

但是我无法从Component A 访问在Components B or C 中声明的任何$refs


我确定这是一个 Vue 生命周期问题,因为如果我直接在主布局中重新创建嵌套组件层次结构(组件 A - C)(不使用在 Component B) 然后我可以通过上述语法毫无问题地访问嵌套的$refs


问题源于Component-A (Layout-Component)中的组件是根据Component B中声明的数据创建的。

布局组件(组件A)片段:

<template v-for="(input, field) in formDialog.inputs">
  <template v-if="Array.isArray(input)">
    <!-- for every record in the input array -->
    <template v-for="(inputArrRecord, arrIndex) in input">
      <v-col cols="12" class="p-0">
        <v-btn
          icon
          x-small
          v-if="arrIndex"
          class="float-right"
          color="error"
          :title="
            inputArrRecord.typeTitle
              ? `Remove $inputArrRecord.typeTitle`
              : 'Remove'
          "
          @click="inputArrRecord.removeAction"
        >
          <v-icon>mdi-close-box-multiple-outline</v-icon>
        </v-btn>
      </v-col>

      <template v-for="(inputArrRecordInput, field2) in inputArrRecord.inputs">
        <!-- for every field in the array record -->
        <dynamic-form-field
          :ref="`dynamicFormField$field2`"
          :input="inputArrRecordInput"
          :field="field2"
          :mode="formMode"
          :error="formDialog.errors[`$field.$arrIndex.$field2`]"
        ></dynamic-form-field>
      </template>
    </template>
  </template>

  <dynamic-form-field
    v-else
    :ref="`dynamicFormField$field`"
    :input="input"
    :field="field"
    :mode="formMode"
    :error="formDialog.errors[field]"
  ></dynamic-form-field>
</template>

数据声明(组件 B)片段:

export default 
  data() 
    return 
      formDialog: 
        errors: [],
        show: false,
        inputs: 
          id: 
            val: '',
            save: true,
            type: 'hidden',
          ,

          word_data: [],
          definitions: [],

          tags: 
            val: [],
            save: true,
            add: true,
            type: 'autocomplete',
            items: this.$root.cache.tags,
            ref: 'vocabTagsAutocomplete',
            label: 'Search For a Tag',
            actionChange: this.addExistingTag,
            actionKeydown: this.addNewTag,
          ,

          synonym: 
            val: '',
            save: true,
            add: true,
            placeholder: 'Synonyms',
          ,
        ,
        titleActions: [
          
            icon: 'mdi-book-plus',
            btnType: 'text',
            text: 'Add Word Type',
            event: this.cloneWordDataTemplate,
          ,
          
            icon: 'mdi-book-plus-outline',
            btnType: 'text',
            text: 'Add Definition',
            event: this.cloneDefinitionTemplate,
          ,
        ],
      ,
    
  ,

dynamic-form-field.vue(组件 C)内容:

<template>
  <v-col
    v-if="(mode == 'add' && input.add) || (mode == 'edit' && input.save)"
    :cols="input.gridSize || 12"
  >
    <form-field-selection
      :input="input"
      :field="field"
      :error="error"
      :ref="`formFieldSelection$field`"
    ></form-field-selection>
  </v-col>
</template>

<script>
  export default 
    name: 'dynamic-form-field',
    props: ['input', 'field', 'mode', 'error'],
  
</script>

如何从组件A访问组件C中声明的$ref

【问题讨论】:

你介意v-for 制作一个引用数组吗? refs 数组不影响通过 ref 访问组件。 【参考方案1】:

您的组件 C 可能正在发出一个事件,将自身作为数据发送:

// Component C
<script>
/*..component code..*/
mounted()
  this.$root.$emit('child_ready',this)

</script>

然后您可以在任何其他组件中听到该事件:

// Your layout
<script>
/*...layout code...*/
created()
    // Using created to make sure we add our listeners before any child mount
    this.$root.$on('child_ready',onChild)
,
beforeDestroy()
    // cleaning the listener
    this.$root.$off('child_ready',onChild)
,
methods:
    onChild(childRef)
        // Now you can access properties and methods
        // childRef.property()
        // childRef.method()
    

<script>

【讨论】:

以上是关于在实现 Vue-Router 的 VueJS SPA 中实现嵌套的 $refs的主要内容,如果未能解决你的问题,请参考以下文章

在 Firebase 托管中使用 vue-router 部署 Quasar (VueJS)

vuejs2:如何将 vuex 存储传递给 vue-router 组件

VueJS 2 vue-router 2 (laravel 5.3)

VueJs(12)---vue-router(导航守卫,路由元信息)

javascript 在URL #vuejs中使用没有哈希的Vue-router

VueJs(11)---vue-router(进阶2)