Day 10 | 嵌套元件(一)

嵌套元件(Nesting Components),在 Vue.js 中是很普遍的用法,可以在父元件赋予数值给子元件进而改变子元件显示的资料。实作中通常会将可重复的内容与主画面分成父子页面,让程序码看起来更简洁更好维护。但在 Livewire 却有些使用上的限制:

子元件虽然可以接收来自父元件的参数,但不能像 Vue 一样即时渲染子元件的内容。
即:透过在元件元素传值的方式只能渲染第一次的值

以下用实际范例来演示:

DEMO网址请点我

首先是父元件

<?php

namespace App\Http\Livewire\Example;

use Livewire\Component;

class Day10 extends Component
{
    public $menu_type;

    public function render()
    {
        return view('livewire.example.day10');
    }
}

<div class="text-center">
    <h2>Day10: 嵌套元件</h2>
    <div class="mb-5">
        <button class="ui button" wire:click="$set('menu_type', '茶')">茶</button>
        <button class="ui button" wire:click="$set('menu_type', '果汁')">果汁</button>
        <button class="ui button" wire:click="$set('menu_type', '咖啡')">咖啡</button>
    </div>
    <h5>目前选的是{{ $menu_type }}</h5>
    @if($menu_type)
        @livewire('example.day10-card', ['menu' => $menu_type])
    @endif
</div>

以及子元件

<?php

namespace App\Http\Livewire\Example;

use Livewire\Component;

class Day10Card extends Component
{
    public $menu;
    
    public function render()
    {
        return view('livewire.example.day10-card');
    }
}

<div class="flex justify-center">
    <div class="rounded shadow-md bg-grey-50 border-2 w-96 p-4">
        <h1>{{ $menu }}的菜单</h1>
        <p>...</p>
    </div>
</div>

在这个范例中,我们设想了一个 电子菜单 的功能,点击上方不同的类别,底下的菜单就会跟着改变。这里我们透过按钮wire:click()与之前提到的魔术方法$set()直接去修改 $menu_type 的值,并在$menu_type有值後显示底下的子元件day10-card

如果是照着 Vue.js 的运行方式,当我们每次更改 $menu_type 的同时,也会对子元件所传入的 $menu 一起做更改,但演示结果并不然。如页面显示,我们在父元件能清楚看到 $menu_type 有确实的更改,但子元件上印出的却不为所动。


解决方法

简单的解决方式则可以在父元件中透过 Lifecycle HooksupdatingFoo$menu_type 有改变时透过 $emit 传递最新的数据给子元件中负责更新 $menu 的函式,如此一来不用动到前端的程序码也能在後端进行资料的同步。

父元件:

由於只要在 $menu_type 有更改时才需要动作,这边就可以用 updatedMenuType 来限缩画面更新时的事件。而 $emit 因为是 全画面的Livewire元件 都会收到,为了避免误传到其他元件中同名的监听函式,所以这里保险一点使用了 $emitTo 并带上 目标元件函式名数值

<?php

namespace App\Http\Livewire\Example;

use Livewire\Component;

class Day10 extends Component
{
    public $menu_type;

    public function render()
    {
        return view('livewire.example.day10');
    }

    /*
        加上 Lifecycle Hooks 的 updated
    */
    public function updatedMenuType($value)
    {
        $this->emitTo('example.day10-card', 'updateMenu', $value);
    }
        
}

子元件:

在子元件的部分 必须 建立一个 $listeners 去监听 $emit 事件,并导向本地的函式。
在上面的父元件我们会$emitupdateMenu 这个名称,并对应到本地的 setMenu() 来改变子元件中 $menu 的值,进而改变页面上的显示。

<?php

namespace App\Http\Livewire\Example;

use Livewire\Component;

class Day10Card extends Component
{
    public $menu;

    public function render()
    {
        return view('livewire.example.day10-card');
    }

    /*
        加上 updateMenu 事件的监听,与对应的更新函式
    */

    protected $listeners = ['updateMenu' => 'setMenu'];
    
    public function setMenu($value)
    {
        $this->menu = $value;
    }
}


<<:  Day 12 - 阴影、透明度使用

>>:  想要回文

Day 27 - 从零开始导入Terraform,Infrastructure as Code Terraform Atlantis

本文同步刊登於个人技术部落格,有兴趣关注更多 Kubernetes、DevOps 相关资源的读者,请...

Day11 Buddy, slab 记忆体管理大将

前言 昨天讲过了远古时代的记忆体管理,跟後续为了解决最古老的记忆体管理所引发的问题而接着有的分段管理...

DAY12 : HTTP前情提要

在实作的过程中,原本想把这篇省略掉,但在往後的实作中,偶而会利用到这些模块与知识,放在这篇,之後文中...

Day 25 - [Android APP] 03-Android 的 STT 与 TTS

用键盘输入讯息,对年轻人或许稀松平常,但对长者而言,使用语音的方式或许更轻松。所以除了画面字体放大外...

Day18 AR头戴式装置 Apple也来凑一咖

在前几期,把AR装置的发展过程大略的描述了一下,从厚重的头戴式装置到可供个人购买的AR眼镜,但这中间...