背景
随着 dcat-admin 越來越多的人使用,相信有許多跟我一樣熱愛這個項目的的人最後也會參與到這個項目中來,從使用者到項目的維護者,可以為項目貢獻一份自己的力量。我以後也會将維護這個項目的一些心得,底層代碼的實作都以博文的形式分享給大家。
需求
有個同學提了一個這樣的需求 ; 需要在表單 / 詳情支援多欄布局,而這個需求剛好我自己用 dcat-admin 做項目時候也遇到過。尤其是 form 表單字段比較多的時候,我開始的解決方案是通過 form 的 tab 來減少表單一頁的字段數量。
表單的多欄目布局
思路:我想的是 form 表單的字段外面包一次 row ,然後控制 row 裡面每個字段的長寬。當我看了 dcat-admin 的代碼後,發現是已經實作好了的,是以不需要自己在開發,我這裡主要講講表單的多欄目布局的用法和底層代碼怎麼實作的。
效果:

使用代碼:
在控制器建立一個 from 方法
protected function form()
{
return Form::make(new WxyMaterialItem(), function (Form $form) {
$form->row(function (Form\Row $row) {
$row->width(4)->text('name')->required();
$row->width(4)->text('id');
$row->width(4)->text('simple_code');
});
$form->row(function (Form\Row $row) {
$row->width(6)->text('integral_money');
$row->width(6)->text('stock_min');
});
$form->row(function (Form\Row $row) {
$row->width(12)->text('attribute');
});
$form->row(function (Form\Row $row) {
$row->width(3)->text('price1');
$row->width(3)->text('price2');
$row->width(3)->text('price3');
$row->width(3)->text('status');
});
});
}
複制
代碼分析:
整個 form 表單渲染出來的流程如下
Dcat\Admin\Form 對象 -> 方法 rows 執行個體化一個 Dcat\Admin\Form\Row 對象并儲存對象屬性 -> 最後通過 render 方法渲染界面
這裡面核心作用檔案是 Dcat\Admin\Form\Row,我們可以看看裡面的幾個方法
width 方法
public function width($width = 12)
{
$this->defaultFieldWidth = $width;
return $this;
}
複制
這個方法主要設定目前行的每一個顯示字段的寬度,比如你一行顯示三個字段
建議每個字段的寬度設定為 3,例如 $row->width (3)->text (‘name’);
__call 方法
public function __call($method, $arguments)
{
$field = $this->form->__call($method, $arguments);
$field->disableHorizontal();
$this->fields[] = [
'width' => $this->defaultFieldWidth,
'element' => $field,
];
return $field;
}
複制
這個方法主要是儲存目前行要顯示的字段的資訊,通過 __call 方法去調用 Dcat\Admin\Form 的字段方法擷取字段資訊,如使用代碼的 $row->width (4)->text (‘name’),會儲存一個寬度 col-md-4 的 Dcat\Admin\Form\Field\Text 字段。
render 方法
public function render()
{
return view('admin::form.row', ['fields' => $this->fields]);
}
複制
admin::form.row 視圖
<div class="row">
@foreach($fields as $field)
<div class="col-md-{{ $field['width'] }}">
{!! $field['element']->render() !!}
</div>
@endforeach
</div>
複制
field [‘element’]->render () 就是将字段渲染成 html 我們可以 dd 下
詳情的多欄目布局
思路:詳情的多欄目布局是需要重新開發的,思路邏輯是和表單的多欄目布局類似的
主要是建立一個 Dcat\Admin\Show\Row 檔案,裡面的代碼如下
<?php
namespace Dcat\Admin\Show;
use Dcat\Admin\Show;
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Support\Collection;
class Row implements Renderable
{
/**
* Callback for add field to current row.s.
*
* @var \Closure
*/
protected $callback;
/**
* Parent show.
*
* @var Show
*/
protected $show;
/**
* @var Collection
*/
protected $fields;
/**
* Default field width for appended field.
*
* @var int
*/
protected $defaultFieldWidth = 12;
/**
* Row constructor.
*
* @param \Closure $callback
* @param Show $show
*/
public function __construct(\Closure $callback, Show $show)
{
$this->callback = $callback;
$this->show = $show;
$this->fields = new Collection();
call_user_func($this->callback, $this);
}
/**
* Render the row.
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function render()
{
return view('admin::show.row', ['fields' => $this->fields]);
}
/**
* @return Collection|\Dcat\Admin\Show\Field[]
*/
public function fields()
{
return $this->fields;
}
/**
* Set width for a incomming field.
*
* @param int $width
*
* @return $this
*/
public function width($width = 12)
{
$this->defaultFieldWidth = $width;
return $this;
}
/**
* Add field.
*
* @param string $name
* @param string $label
*
* @return \Dcat\Admin\Show\Field
*/
public function field($name, $label = '')
{
$field = $this->show->field($name, $label);
$this->pushField($field);
return $field;
}
/**
* Add field.
*
* @param $name
*
* @return \Dcat\Admin\Show\Field|Collection
*/
public function __get($name)
{
$field = $this->show->field($name);
$this->pushField($field);
return $field;
}
/**
* @param $method
* @param $arguments
*
* @return \Dcat\Admin\Show\Field
*/
public function __call($method, $arguments)
{
$field = $this->show->__call($method, $arguments);
$this->pushField($field);
return $field;
}
/**
* @param \Dcat\Admin\Show\Field $field
*
* @return void
*/
protected function pushField($field)
{
$this->fields->push([
'width' => $this->defaultFieldWidth,
'element' => $field,
]);
}
}
複制
裡面 __ cal l, __get , field 三個方法都是擷取目前行的字段資訊,并儲存到行的屬性,在最後渲染詳情的時候先循環 rows(這一步在 Dcat\Admin\Show\Panel 的 render 方法), 在通過上面代碼中的 render 方法渲染 rows 的每個字段;如下:
html 如下
<div class="box-body">
<div class="form-horizontal mt-1">
@if($rows->isEmpty())
@foreach($fields as $field)
{!! $field->render() !!}
@endforeach
@else
<div>
@foreach($rows as $row)
{!! $row->render() !!}
@endforeach
</div>
@endif
<div class="clearfix"></div>
</div>
</div>
複制
使用代碼:
控制器建立一個 detail 方法
protected function detail($id)
{
return Show::make($id, new WxyMaterialItem("brands"), function (Show $show) {
$show->row(function (Show\Row $row) {
$row->width(6)->name;
$row->width(6)->simple_code;
});
$show->row(function (Show\Row $row) {
$row->width(4)->specs;
$row->width(4)->integral_money;
$row->width(4)->field("aa", "你好");
});
$show->row(function (Show\Row $row) {
$row->width(4)->mdept_id("部門");
$row->width(4)->status;
$row->width(4)->field("brands.name", "品牌");
});
});
}
複制