You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel Orchid自定义CodeMirror字段JS失效问题求助

Laravel Orchid自定义CodeMirror字段JS不生效的修复方案

问题描述

在Laravel Orchid中创建支持CodeMirror的自定义字段,完成JS控制器编写、Vite集成、Blade模板、PHP字段类等步骤后,字段仅显示原生textarea,CodeMirror未初始化生效。

核心问题与修复步骤

1. 控制器继承与Stimulus初始化规范问题

Orchid基于Stimulus框架,控制器需正确继承Stimulus的Controller类,且控制器别名需符合短横线命名规范,同时确保Stimulus实例正确初始化。

修改dashboard.js:

import { Application } from '@hotwired/stimulus';
import MirrorTextArea from "./controllers/mirrorTextArea.js";

// 初始化Stimulus应用
window.Stimulus = Application.start();
// 用短横线命名控制器别名,符合Stimulus规范
window.Stimulus.register("mirror-text-area", MirrorTextArea);

2. CodeMirror实例创建逻辑错误

  • 不能将CodeMirror的父容器设为textarea本身,需隐藏原生textarea后在其位置插入编辑器
  • 状态扩展配置错误,未正确添加行号、语言支持等功能
  • 缺少编辑器内容与textarea的同步逻辑,导致表单提交无法获取值

修改JavaScript控制器:

import { EditorState } from '@codemirror/state';
import { EditorView, keymap, lineNumbers, highlightActiveLineGutter } from '@codemirror/view';
import { defaultKeymap } from '@codemirror/commands';
import { sql } from '@codemirror/lang-sql'; // MySQL模式需引入该依赖

export default class extends window.Stimulus.Controller {
    // 定义接收的属性值,自动处理类型转换
    static values = {
        mode: String,
        lineNumbers: Boolean,
        theme: String
    };

    connect() {
        const textarea = this.element.querySelector('textarea');
        textarea.style.display = 'none'; // 隐藏原生textarea

        // 构建CodeMirror扩展数组
        const extensions = [
            keymap.of(defaultKeymap),
        ];

        // 启用行号功能
        if (this.lineNumbersValue) {
            extensions.push(lineNumbers(), highlightActiveLineGutter());
        }

        // 添加SQL语言支持(根据模式调整)
        if (this.modeValue === 'text/x-mysql') {
            extensions.push(sql({ dialect: 'mysql' }));
        }

        // 创建编辑器状态
        const state = EditorState.create({
            doc: textarea.value,
            extensions: extensions
        });

        // 在textarea的父容器中插入编辑器
        const view = new EditorView({
            state,
            parent: textarea.parentElement,
        });

        // 同步编辑器内容到textarea,确保表单提交能获取值
        view.dispatch({
            effects: EditorView.updateListener.of((update) => {
                if (update.docChanged) {
                    textarea.value = view.state.doc.toString();
                }
            })
        });

        view.focus();
    }
}

3. Blade模板数据属性匹配问题

  • 控制器别名需与Stimulus注册的别名一致
  • 数据属性需使用*-value后缀,对应控制器的static values定义
  • textarea的name需使用字段的动态$name属性,而非硬编码

修改Blade模板:

@component($typeForm, get_defined_vars())
    <div data-controller="mirror-text-area"
         data-mirror-text-area-mode-value="{{ $mode }}"
         data-mirror-text-area-line-numbers-value="{{ $line_numbers ? 'true' : 'false' }}"
         data-mirror-text-area-theme-value="{{ $theme }}">
        <textarea name="{{ $name }}" id="editor">{{ $value ?? '' }}</textarea>
    </div>
@endcomponent

4. PHP字段类完善

  • 添加工厂方法,支持链式设置字段属性
  • 确保属性能正确传递到模板,修正字段类型为textarea

修改PHP字段类:

<?php

namespace App\Orchid\Fields;

use Orchid\Screen\Field;

class MirrorTextArea extends Field
{
    protected $view = 'fields.mirror-text-area';

    protected string $type = 'textarea';

    protected $attributes = [
        'mode' => "text/x-mysql",
        'line_numbers' => true,
        'theme' => "default",
    ];

    // 链式设置方法
    public function mode(string $mode): self
    {
        $this->set('mode', $mode);
        return $this;
    }

    public function lineNumbers(bool $status): self
    {
        $this->set('line_numbers', $status);
        return $this;
    }

    public function theme(string $theme): self
    {
        $this->set('theme', $theme);
        return $this;
    }
}

5. 依赖与资源编译验证

  1. 安装缺失的依赖:
npm install @hotwired/stimulus @codemirror/state @codemirror/view @codemirror/commands @codemirror/lang-sql
  1. 编译前端资源:
npm run build
  1. 确保Orchid布局中已加载Vite资源(Orchid默认自动加载,可在resources/views/vendor/orchid/layouts/dashboard.blade.php中确认)

验证使用

在Orchid屏幕中添加字段:

use App\Orchid\Fields\MirrorTextArea;

public function query(): array
{
    return [
        'query' => '', // 初始内容
    ];
}

public function layout(): iterable
{
    return [
        MirrorTextArea::make('query')
            ->mode('text/x-mysql')
            ->lineNumbers(true)
            ->theme('default'),
    ];
}

内容的提问来源于stack exchange,提问作者lan3er

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 02:35:04