laravel-admin 與 vue 結(jié)合使用

laravel-admin 與 vue 結(jié)合使用

由于 Laravel-admin 采用的是 pjax 的方式刷新頁面,意味著很多頁面刷新的操作,并不是刷新整個(gè) document,而是從服務(wù)器拿到部分 document,再通過類似 $(“#pjax-container”).html(newPart) 的方式更新的。

這就造成一個(gè)問題,每次 pjax 刷新,都會(huì)破壞 vue 的 dom 映射。

所以理論上有2種方法解決:

  1. 重新綁定一下 vue 的映射關(guān)系
  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

很多時(shí)候我們并不需要大動(dòng)干戈地建立一個(gè)全部的 view,只需要在內(nèi)置 view 中稍作修改。
這時(shí)候,我們需要先自定義一個(gè) 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());
    }

這樣一來,每次進(jìn)入到 index 頁面,都會(huì)渲染 admin.content 這個(gè) view 。

view 的內(nèi)容直接 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 組件單獨(dú)一個(gè) 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>`,
})

這是一個(gè)彈出式編輯框,具體作用就不解釋了,只是個(gè)示例。

然后還需要在 Admin/bootstrap.php 中引用這個(gè) js 文件:

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

為什么不把組件代碼直接寫進(jìn) view 中呢?
因?yàn)?pjax 的后端邏輯似乎有 bug,template 的內(nèi)容無法全部渲染到前端,導(dǎo)致頁面出錯(cuò)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容