使用Vue.Draggable和laravel实现拖动改变顺序

项目演示

drag.gif

准备工作

  1. 新建laravel项目
laravel new drag
composer install
npm install 

2.安装Vue.Draggabel

npm install vuedraggable 

数据准备

  • 建立series
php artisan make:model Series -m  -c -r

-m:生成migration文件
-c生成controller
-r 生成个resource controller

migration文件

Schema::create('series', function (Blueprint $table) {
            $table->increments('id');
            $table->string('title');
            $table->timestamps();
        });
  • 建立parts
php artisan make:model Parts -m 

migration文件

 Schema::create('parts', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('series_id')->unsigned();
            $table->string('title');
            $table->integer('sort_order');
            $table->timestamps();
        });

Series.php建立关系

public function parts()
    {
        return $this->hasMany(Part::class)->orderBy('sort_order','asc');
    }

使用Seeder填充数据

php artisan make:seeder SeriesTableSeeder
php artisan make:seeder PartsTableSeeder

SeriesTableSeeder.php

 $faker = Faker::create();
 Series::create([
     'title'=>$faker->text(10)
 ]);

PartsTableSeeder.php

$faker = Faker::create();
        for($i=1;$i<5;$i++){
            \App\Part::create([
                'title'=>'Task'.$i,
                'series_id'=>1,
                'sort_order'=>$i
            ]);
        }

使用编写前台代码并且使用Vue.Draggable

<div class="panel panel-default">
                    <div class="panel-heading">Editing <em>{{title}}</em></div>
                    
                    <div class="panel-body">
                        <div class="alert alert-success" v-if="message">
                            {{message}}
                        </div>
                        <form action="#" @submit.prevent="submit">
                            <div class="form-group" v-bind:class="{'has-error':errors.title}">
                                <label for="title" class="control-label">Title</label>
                                <input type="text" name="title" id="title" class="form-control" v-model="title" >
                                <div class="help-block" v-if="errors.title">
                                    {{errors.title[0]}}
                                </div>
                            </div>
                            <draggable :list="parts" :options="{'handle':'.panel-heading'}" @start="drag=true" @end="drag=false " @change="update">
                            <div class="panel panel-default" v-for="part,index in parts">
                                <div class="panel-heading">Part {{index + 1}}({{part.sort_order}})</div>
                                <div class="panel-body">
                                    <div class="form-group" v-bind:class="{'has-error':errors['parts.'+index+'.title']}">
                                        <label>Part Title</label>
                                        <input type="text" name="" id="" class="form-control" v-model="part.title">
                                        <div class="help-block" v-if="errors['parts.'+index+'.title']">
                                            {{errors['parts.'+index+'.title'][0]}}
                                        </div>
                                    </div>
                                </div>
                            </div>
                            </draggable>
                            <div class="form-group">
                                <button type="submit" class="btn btn-primary">Save</button>
                            </div>
                        </form>
                    </div>
                </div>
<script>
    import draggable from 'vuedraggable';
    export default {
        components:{
            draggable
        },
        data(){
            return {
                title: null,
                parts: [],
                errors:[],
                message:null
            }
        },
        props: [
            'data'
        ],
        mounted() {
            this.title = this.data.title;
            this.parts = this.data.parts;
        },
        methods:{
            update(e){
                this.parts.map((part,index)=>{
                    part.sort_order = index + 1
                })
            },
            submit(){
                axios.patch('/series/'+this.data.id,{
                    title:this.title,
                    parts:this.parts
                }).then((response)=>{
                    this.message="Series saved!"
                }).catch((error)=>{
                    this.errors=error.response.data
                })
            }
        }
    }
</script>

后端代码编写

1.路由文件web.php

Route::get('/series/{series}/edit','SeriesController@edit');
Route::patch('/series/{series}','SeriesController@update');

2.生成数据验证

php artisan make:request UpdateSeriesFormRequest
 public function rules()
    {
        return [
            'title' => 'required',
            'parts.*.title' => 'required'
        ];
    }
    public function messages()
    {
        return [
            'title.required' => 'You must enter a series title',
            'parts.*.title.required'=> 'You need to give this part a title'
        ];
    }

3.创建队列任务

php artisan queue:table
php artisan queue:failed-table
php artisan make:job UpdateSeriesParts
 public function __construct(Series $series,$parts)
    {
        //
        $this->series = $series;
        $this->parts = $parts;
    }
public function handle()
    {
        $this->series->parts->each(function ($part,$index) {
            $part->update(array_only($this->parts[$index],['title','sort_order']));
        });
    }

开启队列监听

php artisan queue:listen 

4.Controller文件

public function edit(Series $series)
    {
        $series->load('parts');
        return view('series.edit',compact('series'));
    }
public function update(UpdateSeriesFormRequest $request, Series $series)
    {
        
        $series->title=$request->title;
        $series->save();
        dispatch(new UpdateSeriesParts($series,$request->parts));
        return response(null,200);
    }

这是codecourse上的Demo,使用了Vue作为前端,Vue.draggable实现拖动,axios发送请求(laravel5.4现在默认就是axios)后端使用Laravel,包括数据填充,数据验证,建立模型,队列等效知识点,希望有助于大家今后用laravel和vue做开发

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,978评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,954评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,623评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,324评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,390评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,741评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,892评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,655评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,104评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,569评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,254评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,834评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,725评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,950评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,260评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,446评论 2 348

推荐阅读更多精彩内容