laravel-admin 与 vue 结合使用

laravel-admin 与 vue 结合使用

由于 Laravel-admin 采用的是 pjax 的方式刷新页面,意味着很多页面刷新的操作,并不是刷新整个 document,而是从服务器拿到部分 document,再通过类似 $(“#pjax-container”).html(newPart) 的方式更新的。

这就造成一个问题,每次 pjax 刷新,都会破坏 vue 的 dom 映射。

所以理论上有2种方法解决:

  1. 重新绑定一下 vue 的映射关系
  2. 在某些页面禁止 pjax

1 太难搞,而且没啥资料,放弃。2 的话比较可行。

部分禁止 pjax

打开 public/vendor/laravel-admin/laravel-admin/laravel-admin.js
添加代码:

// 不使用 pjax 刷新的页面
$(document).on('pjax:beforeReplace', function (e, options) {
  // console.log(arguments)
  var freshPaths = [
    /\/admin.*\/products/,
  ]
  for (let path of freshPaths) {
    if (path.test) {
      if (path.test(e.state.url)) {
        location.reload()
        return false
      }
    }
    else if (options.url.search(path) !== -1) {
      location.reload()
      return false
    }
  }
})

使用自定义 view

很多时候我们并不需要大动干戈地建立一个全部的 view,只需要在内置 view 中稍作修改。
这时候,我们需要先自定义一个 Content 类:

use Encore\Admin\Layout\Content;

class MyContent extends Content {
    public function render() {
        $items = [
            'header'      => $this->header,
            'description' => $this->description,
            'breadcrumb'  => $this->breadcrumb,
            'content'     => $this->build(),
        ];

        return view('admin.content', $items)->render();
    }
}

然后引用它:

    public function index(MyContent $content) {
        return $content
            ->header('product')
            ->description($this->brand)
            ->body($this->grid());
    }

这样一来,每次进入到 index 页面,都会渲染 admin.content 这个 view 。

view 的内容直接 copy 自 vendor/encore/laravel-admin/resources/views/content.blade.php

在 view 里插入 vue 组件

添加2部分代码即可。
第一部分是初始化 vue app:

    <script data-exec-on-popstate>
    // boot up the demo
    $(function () {

      // vapp
      window.vapp = new Vue({
        el: '#app',
        data () {
          return {
            status: {
              showGalleryEditor: false,
            },
            store: {
              images: [],
              el: '',
            },
          }
        },
        components: {},
        methods: {
          startGalleryEditing (event) {
            this.status.showGalleryEditor = true
            this.store.pk = $(event.target).parent().find('ul').data('pk')
            this.store.images = $(event.target).parent().find('img').toArray().map((e) => e.getAttribute('src'))
            window.p = $(event.target).parent().find('ul')
          },
        },
      })
    })
    </script>

第2部分是插入组件:

        <gallery-editor :status="status" :images="store.images" :pk="store.pk"></gallery-editor>

vue 组件单独一个 js 文件

位置如下:public/vendor/components/gallery-editor.js
定义如下:

Vue.component('gallery-editor', {
  props: {
    status: {
      showGalleryEditor: false,
    },
    images: [],
    pk: 0,
    moveTo: [],
  },
  data () {
    return {}
  },
  watch: {
    images (newVal, oldVal) {
      this.moveTo = []
      for (let src of newVal) {
        this.moveTo.push({
          src: src,
          productId: this.pk,
          deleted: 0,
        })
      }
    },
  },
  methods: {
    close () {
      this.status.showGalleryEditor = false
    },
    save () {
      let args = {_token: LA.token}
      args.id = this.pk
      args.images = []
      args.move_to = []

      // console.log(JSON.stringify(this.moveTo))
      for (let imgObj of this.moveTo) {
        if (imgObj.deleted) {
          continue
        }
        if (imgObj.productId === this.pk) {
          args.images.push(imgObj.src)
        } else {
          args.move_to.push({src: imgObj.src, product_id: imgObj.productId})
        }
      }
      // console.log(JSON.stringify(args))
      $.post('/admin/products/move-images', args).done(() => {
        toastr.success('success')
        this.status.showGalleryEditor = false
      }).fail((response) => {
        toastr.error(response.responseText)
      })
    },
  },
  template: `
            <div class="modal" tabindex="-1" role="dialog" :class="{show: status.showGalleryEditor, fade: !status.showGalleryEditor}">
              <div class="modal-dialog" role="document">
                <div class="modal-content">
                  <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close" @click="close"><span aria-hidden="true">&times;</span></button>
                    <h4 class="modal-title">Editing images</h4>
                  </div>
                  <div class="modal-body">
                  <ul style="list-style-type: none;">
                      <li v-for="(imageObj, key) in moveTo" :key="key" style="margin-bottom: 8px">
                          <img :src="imageObj.src" alt="" style="width:40px;height:40px">
                          <label>Move to product: <input type="text" v-model="imageObj.productId"></label>
                          <label>Delete:<input type="checkbox" v-model="imageObj.deleted"></label>
                    </li>
                    </ul>
                  </div>
                  <div class="modal-footer">
                    <button type="button" class="btn btn-default" data-dismiss="modal" @click="close">Close</button>
                    <button type="button" class="btn btn-primary" @click="save">Save changes</button>
                  </div>
                </div>
              </div>
            </div>`,
})

这是一个弹出式编辑框,具体作用就不解释了,只是个示例。

然后还需要在 Admin/bootstrap.php 中引用这个 js 文件:

Admin::js('/vendor/components/gallery-editor.js');

为什么不把组件代码直接写进 view 中呢?
因为 pjax 的后端逻辑似乎有 bug,template 的内容无法全部渲染到前端,导致页面出错。

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

推荐阅读更多精彩内容