Nova 随附各种字段类型,但有时你可能需要的字段类型并不是开箱即有的。因此,Nova 允许你创建自定义字段。自定义字段由三个 Vue 组件组成,它们决定了字段在不同上下文中的显示方式。
自定义字段可使用 nova:field Artisan 命令生成。默认情况下,所有新字段都将放在应用程序的 nova-components 目录中。使用nova:field命令生成字段时,传递给命令的字段名称应遵循 Composer 的 vendor/package 格式。因此,如果我们要创建一个 color-picker 字段,可以运行以下命令:
php artisan nova:field acme/color-picker生成字段时,Nova 会提示你安装字段的 NPM 依赖项、编译其资产并更新应用程序的 composer.json 文件。所有自定义字段都会在应用程序中注册为 Composer 「路径」存储库。
Nova 字段包含构建字段所需的所有脚手架。每个字段甚至都包含自己的 composer.json 文件,可以在 GitHub 或你选择的源控制提供商上与全世界共享。
Nova 字段可在资源的 fields 方法中注册。该方法返回资源可用字段的数组。要注册字段,请将字段添加到此方法返回的字段数组中:
use Acme\ColorPicker\ColorPicker;
/**
* 获取资源显示的字段。
*
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
* @return array
*/
public function fields(NovaRequest $request)
{
return [
ID::make('ID', 'id')->sortable(),
ColorPicker::make('Color'),
];
}通常,你需要允许字段的用户自定义字段的运行时配置选项。为此,你可以在字段类上公开方法。这些方法可调用字段的底层 withMeta 方法,以向字段的元数据添加信息,这些信息将在字段的 Vue 组件中提供。withMeta 方法接受一个键/值选项数组:
<?php
namespace Acme\ColorPicker;
use Laravel\Nova\Fields\Field;
class ColorPicker extends Field
{
/**
* 字段的组成部分。
*
* @var string
*/
public $component = 'color-picker';
/**
* 设置颜色选择器可选择的色调。
*
* @param array $hues
* @return $this
*/
public function hues(array $hues)
{
return $this->withMeta(['hues' => $hues]);
}
}你的字段的 Vue 组件会收到一个 field Vue prop。 field 属性提供了对任何可用字段选项的访问:
const hues = this.field.hues;Nova 生成的每个字段都有自己的服务提供者和 "field" 类。以 color-picker 字段为例,字段类将位于 src/ColorPicker.php。
字段的服务提供者也位于字段的 src 目录中,并在字段的 composer.json 文件的 extra 部分注册,以便 Laravel 自动加载。
当Nova生成你的字段时,它会创建一个 resourcesjscomponentsIndexField.vue vue组件。当字段显示在资源索引页上时,此组件包含字段的模板和逻辑。默认情况下,该组件只是在一个简单的 <span> 元素中显示字段的值;但是,你可以根据需要自由修改此字段组件。
创建字段时,Nova 还会创建一个 resources/js/components/DetailField.vue Vue 组件。该组件包含字段在资源详情页显示时的模板和逻辑。默认情况下,该模板包含显示字段值所需的必要标记。不过,你可以根据应用程序的需要自由调整该模板。
最后,Nova 会创建一个 resources/js/components/FormField.vue Vue 组件。该组件包含字段在创建或更新表单中显示时的模板和逻辑。默认情况下,该模板包含一个简单的 input 控件,用于修改字段的底层值;不过,你可以自由定制该模板。例如,我们可以更新模板以显示一个颜色选择器控件:
<template>
<DefaultField :field="field">
<template #field>
<input :id="field.name" type="color"
class="w-full form-control form-input form-input-bordered"
:class="errorClasses"
:placeholder="field.name"
v-model="value"
/>
<p v-if="hasError" class="my-2 text-danger">
{{ firstError }}
</p>
</template>
</DefaultField>
</template>
<script>
import { FormField, HandlesValidationErrors } from 'laravel-nova'
export default {
mixins: [FormField, HandlesValidationErrors],
//
}
</script>在创建或更新资源之前,Nova 会要求表单上的每个字段用 键/值对「填充」传出的 FormData 对象。每个字段可根据需要向 FormData 添加任意数量的元素。这可在你的 FormField.vue 文件的 fill 方法中完成:
/**
* 用字段的内部值填充给定的 FormData 对象。
*/
fill(formData) {
this.fillIfVisible(formData, this.fieldAttribute, this.value || '')
}默认情况下,所有自定义字段都将使用 FormField 混合元素创建。但是,如果你正在创建 依赖字段,则应将 FormField 替换为 DependentFormField:
// 之前 ...
import { FormField, HandlesValidationErrors } from 'laravel-nova'
export default {
mixins: [FormField, HandlesValidationErrors],
//
}
// 之后...
import { DependentFormField, HandlesValidationErrors } from 'laravel-nova'
export default {
mixins: [DependentFormField, HandlesValidationErrors],
//
}接下来,在 Vue 模板中,通常应使用 this.currentField 而不是 this.field 来引用字段:
<template>
<DefaultField :field="currentField" :errors="errors">
<template #field>
<input
:id="currentField.uniqueKey"
type="text"
class="w-full form-control form-input form-input-bordered"
:class="errorClasses"
:placeholder="currentField.placeholder"
v-model="value"
/>
<p v-if="hasError" class="my-2 text-danger">
{{ firstError }}
</p>
</template>
</DefaultField>
</template>
<script>
import { DependentFormField, HandlesValidationErrors } from 'laravel-nova'
export default {
mixins: [DependentFormField, HandlesValidationErrors],
//
}
</script>接下来,别忘了在你的 Field 类上使用 Laravel\Nova\Fields\SupportsDependentFields 特性:
use Laravel\Nova\Fields\Field;
use Laravel\Nova\Fields\SupportsDependentFields;
class ColorPicker extends Field
{
use SupportsDependentFields;
// ...
}默认情况下,在保存模型时,你的字段类只需将传入的表单字段值复制到字段的关联模型属性中。不过,你可以自定义字段如何水合资源模型。要做到这一点,请覆盖字段类上的 fillAttributeFromRequest 方法:
<?php
namespace Acme\ColorPicker;
use Illuminate\Support\Str;
use Laravel\Nova\Fields\Field;
use Laravel\Nova\Http\Requests\NovaRequest;
class ColorPicker extends Field
{
/**
* 字段的组成部分。
*
* @var string
*/
public $component = 'color-picker';
/**
* 用数据填充模型的属性。
*
* @param \Illuminate\Database\Eloquent\Model|\Laravel\Nova\Support\Fluent $model
* @param mixed $value
* @param string $attribute
* @return void
*/
public function fillModelWithData(mixed $model, mixed $value, string $attribute)
{
$attributes = [Str::replace('.', '->', $attribute) => $value];
$model->forceFill($attributes);
}
}该方法接收多个参数。当然,它接收传入的 HTTP 请求和正在更新的模型。该方法还会接收 $requestAttribute,即 HTTP 请求中传入表单字段的名称。此外,它还会接收 $attribute,即字段值应放置的模型属性名称。
Nova 生成字段时,会为你生成 resources/js 和 resources/css 目录。这些目录包含字段的 JavaScript 和 CSS。
你的 Nova 字段服务提供商会注册你的字段编译资源,以便 Nova 前端可以使用这些资源:
use Laravel\Nova\Nova;
use Laravel\Nova\Events\ServingNova;
/**
* 引导任何应用服务。
*
* @return void
*/
public function boot()
{
Nova::serving(function (ServingNova $event) {
Nova::script('stripe-inspector', __DIR__.'/../dist/js/field.js');
Nova::style('stripe-inspector', __DIR__.'/../dist/css/field.css');
});
}JavaScript 引导和路由
你的组件将在 resources/js/field.js 文件中引导和注册。你可以根据需要修改该文件或在此注册其他组件。
Nova 字段包含一个 webpack.mix.js 文件,该文件在 Nova 创建工具时生成。你可以使用 NPM dev 和 prod 命令构建你的工具:
# 准备 Laravel Nova 的依赖项...
npm run nova:install
# 为本地开发编译资源...
npm run dev
# 编译并最小化资源...
npm run prod此外,你还可以运行 NPM watch 命令,在资源发生变化时自动编译它们:
npm run watchnova:install NPM 命令
nova:install NPM 命令会安装 Nova 内置字段使用的 mixins,以便在你的字段中使用。更多信息请参阅 Nova mixins 文档。