Vue.js 的正規開發方式建議使用屬性及事件對其他組件做處理,但還是會有一些情境中會需要直接使用其他組件的各種功能, Vue.js 也提供了這些尋訪的方式。
可以在任何的子組件中使用 $root 取得根實體,如下例所示:
Vue.component('first-layer', {
  template: `<div>
    I am First Layer. $root.a: {{$root.a}}
    <button @click="$root.adda()">Add a</button>
    <second-layer></second-layer>
  </div>`
});
Vue.component('second-layer', {
  template: `<div>
    I am Second Layer. $root.a: {{$root.a}}
    <button @click="$root.adda()">Add a</button>
  </div>`
});
var vm = new Vue({
  el: '#app',
  data: {
    a: 1
  },
  methods: {
    adda: function() {
      this.a += 1;
    }
  }
});
<div id="app">
  <first-layer></first-layer>
</div>
有兩個階層的組件: first-layer 及 second-layer ,這兩個組件中都用 $root.a 取得存在於根實體中的 a 資料,以及使用 $root.adda() 叫用只存在於根實體中的 adda 方法。
與尋訪根實體的方式相似, Vue.js 提供了 $parent 這個物件使我們可以取得父組件實體。
延續上節的例子,在 first-layer 中使用 $parent 操作根實體的資料 a :
Vue.component('first-layer', {
  template: `<div>
    I am First Layer. 
    $root.a: {{$root.a}}
    <button @click="$root.adda()">Add a by $root.adda()</button>
    <button @click="$parent.adda()">Add a by $parent.adda()</button>
  </div>`
});
檔案下 Add a by $parent.adda() 按鈕時,也可以看到根實體的資料 a 的數值變化。
當然 $parent 在多階層組件下還是可以運作的:
Vue.component('first-layer', {
  ...
  data: function() {
    return {
      b: 0
    };
  },
  methods: {
    minusb: function() {
      this.b -= 1;
    }
  }
});
Vue.component('second-layer', {
  template: `<div>
    I am Second Layer.
    $root.a: {{$root.a}}
    <button @click="$root.adda()">Add a</button>
    $parent.b: {{$parent.b}}
    <button @click="$parent.minusb()">Minus b</button>
  </div>`
});
在 first-layer 組件中加入資料 b 以及 minusb() 這個對 b 做減一的方法,在 second-layer 中使用 $parent 依然可以取得其父組件 first-layer 的實體。
子組件的尋訪是使用 $children 物件:
<div id="app">
  <first-layer></first-layer>
</div>
var vm = new Vue({
  el: '#app',
  data: {
    a: 1
  },
  mounted: function() {
    console.log(this.$children[0].b);   // 0
  },
  methods: {
    adda: function() {
      this.a += 1;
    }
  }
});
因為子組件是複數的,所以使用陣列來存取,使用 $children[0].b 就可以取得 first-layer 的實體。
$children不保證組件的順序,意即不能直接看模板上的順序確定組件在$children陣列中的位置。
$ref不一定每個子組件都是尋訪的目標,因此使用 $children 總會需要另外的處理才能找到目標的子組件,本節介紹的 ref 屬性可以在子組件上設定,代表這個子組件是我們想要尋訪的目標:
<base-input ref="customInput"></base-input>
如此一來,我們就可以使用 $ref.customInput 取得這個子組件的實體。
以剛才的 base-input 做衍伸,通常這類的基底組件都會搭配 HTML 原生元素,如下所示:
Vue.component('base-input', {
  template: `<div>
    I am a input component.
    <input ref="input"></input>
  </div>`,
  methods: {
    focus: function() {
      this.$refs.input.focus()
    }
  }
});
我們可以將 ref 的屬性用在原生元素上,這樣就可以直接做原生地操作了(像是 focus())。
在外層的組件中使用 base-input 也可以藉由 focus() 方法,以原生元素的方式使用 base-input :
<button @click="$refs.customInput.focus()">focus input</button>
v-for 搭配當子組件以 v-for 渲染出多個時,原本的物件會以陣列的形式處理複數的子組件實體:
<base-input v-for="n in 10" ref="moreInput"></base-input>
<button @click="$refs.moreInput[0].focus()">focus input[0]</button>
上面這些直接尋訪的方式比起之前介紹的 props 及 event 的方式簡單許多,但這樣的方式會對開發造成很大的問題,你的程式會變得:
因此在大型專案中應避免使用這類的方式。
我們可以使用 $root 直接取得根實體, $parent 取得父組件實體,以及 $children 取得子組件實體,而子組件實體的尋訪可以使用 $ref 來做更精確的操作及定位。