如何使用上下文菜单创建 JSTree 视图,并使用 PHP/Laravel 创建、重命名、删除、拖放?这是完整的解决方案

如何解决如何使用上下文菜单创建 JSTree 视图,并使用 PHP/Laravel 创建、重命名、删除、拖放?这是完整的解决方案

我的项目需要一个文件树视图来上传文档,我使用了一个主题森林模板,页面中包含了 jstree。

所以我决定使用它,但有必要将它连接到数据库。它需要一个数据库、一个 api 和它的所有代码。

我花了几个小时试图找出如何使用 Laravel 创建 JSTree 结构,包括拖放、移动、创建、重命名和排序功能。

解决方法

在深入研究 jstree 文档和 Stack Overflow 之后,这里是我对所有内容的工作解决方案的逐步编译。

我使用的是 JSTree 版本 3.3.11 和 Laravel 8。

步骤:

A) 创建数据库。 该表是“目录”。

    class CreateDirectoriesTable extends Migration
    {
        public function up()
        {
            Schema::create('directories',function (Blueprint $table) {
                $table->id();
                $table->unsignedBigInteger('parent_id')->nullable();
                $table->string('name');
                $table->text('observations')->nullable();
                $table->timestamps();
    
                $table->foreign('parent_id')
                    ->references('id')
                    ->on('directories')
                    ->cascadeOnDelete();
    
            });
        }
    
        /**
         * Reverse the migrations.
         *
         * @return void
         */
        public function down()
        {
            Schema::dropIfExists('directories');
        }
    }

B) 目录.model 使用它来定义哪些字段是可更新的,并定义递归关系。

    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Factories\HasFactory;
    use Illuminate\Database\Eloquent\Model;
    
    class Directory extends Model
    {
        use HasFactory;
        
        protected $fillable = [
            'parent_id','name','observations',];
    
        public function children()
        {
            return $this->hasMany(Directory::class,'parent_id');
        }
    
    }

C) 播种机(可选) 我使用 Seeder 来包含一些要测试的项目

<?php

namespace Database\Seeders;

use Faker\Factory;
use App\Models\Directory;
use Illuminate\Database\Seeder;

class DirectorySeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $faker = Factory::create();

        $items = array(
            [
                'name' => $faker->lexify('???????????????'),'parent_id' => null,'observations' => $faker->optional()->paragraph(3),],[
                'name' => $faker->lexify('???????????????'),'parent_id' => 1,'parent_id' => 2,'parent_id' => 3,'parent_id' => 5,'parent_id' => 7,'parent_id' => 8,);
        
        foreach($items as $item) { 
            Directory::factory()->create($item);         
        }    
    }
}

D) web.php 上的路由 我已经定义了 4 个函数来处理 DragNDrop、Rename、Delete 和 Create。

Route::name('api.')->prefix('api/')->group(function() {
    Route::post('/treeview/dnd','ApiController@treeviewDnd')->name('treeviewdnd');
    Route::post('/treeview/rename','ApiController@treeviewRename')->name('treeviewrename');
    Route::post('/treeview/delete','ApiController@treeviewDelete')->name('treeviewdelete');
    Route::post('/treeview/create','ApiController@treeviewCreate')->name('treeviewcreate');
});

E) API 控制器

class ApiController extends Controller
{
    // Move Node on Directory Tree
    public function treeviewDnd()
    {
        $directory = Directory::find(request()->source);
        if ($directory) {
            if (request()->destination) {
                if (request()->destination == '#') {
                    $directory->parent_id = null;
                } else {
                    $directory->parent_id = request()->destination;
                }
            } 
            $directory->update();
        }
    }

    // Rename Node on Directory Tree
    public function treeviewRename()
    {
        $directory = Directory::find(request()->dbid);
    
        if ($directory) {
            $name = request()->name;
            if ($name) {            
                $directory->name = $name;
                $directory->update();
            }    
        }
    }

    // Delete Node on Directory Tree
    public function treeviewDelete()
    {        
        $directory = Directory::find(request()->id);
        
        if ($directory) {
            $directory->delete();
        }

    }

    // Create Node on Directory Tree
    public function treeviewCreate()
    {
        $directory = [
            "name" => request()->name,"parent_id" => request()->parentid,];
        $result = Directory::create($directory);
        
        return $result;
    }
}

F) 在blade.php 中包含树

<div id="stackoverflowtree" class="tree-demo"></div>

G) 我在我的基本刀片上创建了一个“脚本”部分,所以我可以使用部分标签在页面末尾包含脚本。

@section('scripts')

    <script>
        "use strict";
        var tree = {!! $treeJS !!};
        var treeId = '#stackoverflowtree';

        var nodeSelected = undefined;
        
        var KTTreeview = function () {
            var _demostackoverflow = function() {
                $(treeId).jstree({
                    "core" : {
                        "themes" : {
                            "responsive": false
                        },// so that create works
                        "check_callback" : function (operation,node,node_parent,node_position,more) {
                            if (operation === 'delete_node') {
                                if (confirm('@lang("global.confirmation_title")') == true) {
                                    return true;
                                }
                                else {
                                    return false;
                                }
                            } else {
                                return true;
                            }
                        },'data': tree,},"types" : {
                        "default" : {
                            "icon" : "fa fa-folder text-primary"
                        },"file" : {
                            "icon" : "fa fa-file text-primary"
                        }
                    },"state" : { "key" : "demo2" },"plugins" : [ "dnd","state","types","sort","contextmenu" ],"sort" : function(a,b) {                
                        if (a && b && this) {
                            var a1 = this.get_node(a);
                            var b1 = this.get_node(b);
                            
                            if (a1.icon == b1.icon){
                                return a1.text.toLowerCase().localeCompare(b1.text.toLowerCase());
                            } else {
                                return a1.icon.toLowerCase().localeCompare(b1.icon.toLowerCase());
                            }
                        }
                    },"contextmenu": {
                        "items": function ($node) {
                            var tree = $(treeId).jstree(true);
                            return {
                                "Rename": {
                                    "label": "@lang('global.directory_rename')","action": function (obj) { 
                                        tree.edit($node);
                                    }
                                },"Create": {
                                    "label": "@lang('global.directory_create')","action": function (obj) { 
                                        $node = tree.create_node($node);
                                        tree.edit($node); 
                                    }
                                },"Delete": {
                                    "label" : "@lang('global.directory_delete')","action" : function(obj) { 
                                        tree.delete_node($node);
                                    }
                                }
                            };
                        }
                    }
                })
                .bind("move_node.jstree",function(e,data) {
                    var treeInst = $(treeId).jstree(true);
                
                    var parentNodeResult = null;
                    if (data.parent != '#') {
                        var aux = treeInst.get_node(data.parent);
                        parentNodeResult = aux.original.dbid;
                    } else {
                        parentNodeResult = '#';
                    }
                
                    $.ajax({
                        url: "{{ route('api.treeviewdnd') }}",type:'POST',data: {
                            "_token" : "{{ csrf_token() }}","source": data.node.original.dbid,"destination": parentNodeResult,success: function(data) {
                            console.log(data);
                        }
                    });
                })
                .bind("select_node.jstree",function(evt,data){
                    console.log("select");
                    nodeSelected = data.node;

                    $("#tree-subtitle").html(data.node.text)
                    
                })
                .bind("rename_node.jstree",function (e,data) {    
                    if (data.node.text && data.text != data.old) {    
                        
                        $.ajax({
                            url: "{{ route('api.treeviewrename') }}",data: {
                                "_token" : "{{ csrf_token() }}","dbid": data.node.original.dbid,"name": data.text,success: function(data) {
                                toastr.success('@lang("global.success_message")','@lang("global.success_title")');
                            },error: function(data) {
                                toastr.error('@lang("global.error_required")','@lang("global.error_title")');
                            }
                        });
                    }    
                })
                .bind("create_node.jstree",data) {    

                    var treeInst = $(treeId).jstree(true)
                    var parentNode = treeInst.get_node(data.parent)
                    
                    $.ajax({
                        url: "{{ route('api.treeviewcreate') }}","entityid": {{ $entity->id }},"parentid": parentNode.original.dbid,"name": data.node.text,success: function(response) {
                            data.node.original = { "dbid" : response.id };
                        },error: function(response) {
                            toastr.error('@lang("global.error_message")','@lang("global.error_title")');
                        }
                    });
                    
                })
                .bind("delete_node.jstree",data) {
                    $.ajax({
                        url: "{{ route('api.treeviewdelete') }}","id": data.node.original.dbid,success: function(data) {
                            toastr.success('@lang("global.success_message")','@lang("global.success_title")');
                        },error: function(data) {
                            toastr.error('@lang("global.error_message")','@lang("global.error_title")');
                        }
                    });
                
                });
            }

            
            return {
                //main function to initiate the module
                init: function () {
                    _demostackoverflow();
                }
            };
        }();        
        
        jQuery(document).ready(function() {
            KTTreeview.init();
        });
     
    </script>
@endsection

H) 我差点忘了。服务器端树结构的创建,页面Controller:

<?php

namespace App\Http\Controllers;

use App\Models\Directory;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class EntityController extends Controller
{

    private function getTreeJS($entity,$path_id,&$treejs)
    {
        
        $directories = Directory::where('entity_id',$entity->id)->where('parent_id',$path_id)->get();
        
        $treejs .= '[';
        foreach($directories as $directory) {
            $treejs .= '{';
                $treejs .= '    "dbid" : "' . $directory->id . '",';
                $treejs .= '    "text" : "' . $directory->name . '",';
                
                $treejs .= '"children" : ';
                
            $treejs .= $this->getTreeJS($entity,$directory->id,$treejs);
            
        
            $treejs .= '},';
        }
        $treejs .= ']';
    }

    public function details(Entity $entity,Property $property = null)
    {
        // Create Tree JS
        $treejs = '';
        $this->getTreeJS($entity,null,$treejs);
        
        return view('admin.entities.details',[
            'treeJS' => $treejs,]);
    }
}

I) 我用来向用户显示一些输出的消息位于 Laravel 中的语言文件 /resources/lang/en/ 中:

<?php

return [
    // Success
    'success_title' => 'Success!','success_message' => 'Operation successfully.',// Errors
    'error_title' => 'Ups! There was an error.','error_required' => 'You must fill the information.','error_message' => 'It was not possible to finish the operation.','confirmation_title' => 'Do you confirm?','confirmation_success' => 'Operation successfully.','directory_rename' => 'Rename','directory_create' => 'Create folder','directory_delete' => 'Delete folder'
];

结论: 对于与数据库表中的 ID 相对应的每个树文件夹,我都使用了一个名为 dbid 的额外变量。

使用该数据库 ID,我可以通过使用 jstree 'get_node' 查找确切节点来在每个操作中使用它。

我刚刚开始学习 Laravel,这不是完美的解决方案,但这是我处理需求的方法。随意使用它并按照自己的方式进行更改。

这是我的图片:

Jstree context menu

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res