Nova 附带了各种字段类型;但是,有时您可能需要一个开箱即用时未提供的字段类型。为此,Nova 允许您构建自定义字段。自定义字段由三个 Vue 组件组成,这些组件决定了字段在各种上下文中的显示方式。
可以使用 nova:field
Artisan 命令生成自定义字段。默认情况下,所有新字段都将放置在应用程序的 nova-components
目录中。使用 nova:field
命令生成字段时,传递给命令的字段名称应遵循 Composer vendor/package
格式。因此,如果我们正在构建一个颜色选择器字段,我们可能会运行以下命令
php artisan nova:field acme/color-picker
生成字段时,Nova 会提示您安装字段的 NPM 依赖项,编译其资源并更新应用程序的 composer.json
文件。所有自定义字段都作为 Composer "path" 存储库 与您的应用程序注册。
Nova 字段包含构建字段所需的所有脚手架。每个字段甚至包含自己的 composer.json
文件,并且已准备好与 GitHub 或您选择的源代码控制提供商共享。
Nova 字段可以在资源的 fields
方法中注册。此方法返回资源可用的字段数组。要注册您的字段,请将您的字段添加到此方法返回的字段数组中
use Acme\ColorPicker\ColorPicker;
/**
* Get the fields displayed by the resource.
*
* @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
{
/**
* The field's component.
*
* @var string
*/
public $component = 'color-picker';
/**
* Set the hues that may be selected by the 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 生成的每个字段都包含自己的服务提供商和“字段”类。以 color-picker
字段为例,字段类将位于 src/ColorPicker.php
中。
该字段的服务提供者也位于字段的src
目录中,并在字段的composer.json
文件的extra
部分中注册,以便 Laravel 自动加载它。
当 Nova 生成您的字段时,它会创建一个resources/js/components/IndexField.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
方法中完成
/**
* Fill the given FormData object with the field's internal value.
*/
fill(formData) {
this.fillIfVisible(formData, this.fieldAttribute, this.value || '')
}
默认情况下,所有自定义字段都将创建为使用FormField
混合。但是,如果您正在构建一个依赖字段,则应将FormField
替换为DependentFormField
// Before ...
import { FormField, HandlesValidationErrors } from 'laravel-nova'
export default {
mixins: [FormField, HandlesValidationErrors],
//
}
// After...
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
{
/**
* The field's component.
*
* @var string
*/
public $component = 'color-picker';
/**
* Fill the model's attribute with data.
*
* @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;
/**
* Bootstrap any application services.
*
* @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` 命令来构建你的字段。
# Prepare Laravel Nova's dependencies...
npm run nova:install
# Compile your assets for local development...
npm run dev
# Compile and minify your assets...
npm run prod
此外,你还可以运行 NPM 的 `watch` 命令,以便在资产发生更改时自动编译它们。
npm run watch
`nova:install` NPM 命令
`nova:install` NPM 命令会安装 Nova 内置字段使用的 mixin,以便在你的字段中使用。有关更多信息,请参阅 Nova mixin 文档。