組件繼承----基于Vue和PHP打造前后端分離的通用管理系統(tǒng)(七)

不知不覺已寫到第7篇。前面6篇都是探索性的實現(xiàn),是學(xué)習(xí)理論的過程,從這篇開始,開始用理論來指導(dǎo)實踐了。
接上篇,我們現(xiàn)在通過組件繼承實現(xiàn)Admin頁面內(nèi)導(dǎo)航。

動態(tài)導(dǎo)航

我們要的導(dǎo)航,是根據(jù)登錄用戶的權(quán)限,顯示不同的導(dǎo)航菜單。根據(jù)職能分工,菜單內(nèi)容的確定由后端來做更符合實踐,前端只需要實現(xiàn)動態(tài)渲染菜單即可。好在這是Vue擅長的。


頁內(nèi)跳轉(zhuǎn).PNG

在components目錄下新建Aside.vue。在Aside.vue中放置一個el-menu,我們先用一個靜態(tài)的占個位,然后實現(xiàn)成動態(tài)的。靜態(tài)的我們直接用ElemenUI自己的例子好了。

<template>
  <el-row>
    <el-col :span="24">
      <h5>管理后臺</h5>
      <el-menu
        default-active="2"
        class="el-menu-vertical-demo"
        background-color="#545c64"
        text-color="#fff"
        active-text-color="#ffd04b">
        <el-submenu index="1">
          <template slot="title">
            <i class="el-icon-location"></i>
            <span>導(dǎo)航一</span>
          </template>
          <el-menu-item-group>
            <template slot="title">分組一</template>
            <el-menu-item index="1-1">選項1</el-menu-item>
            <el-menu-item index="1-2">選項2</el-menu-item>
          </el-menu-item-group>
          <el-menu-item-group title="分組2">
            <el-menu-item index="1-3">選項3</el-menu-item>
          </el-menu-item-group>
          <el-submenu index="1-4">
            <template slot="title">選項4</template>
            <el-menu-item index="1-4-1">選項1</el-menu-item>
          </el-submenu>
        </el-submenu>
        <el-menu-item index="2">
          <i class="el-icon-menu"></i>
          <span slot="title">導(dǎo)航二</span>
        </el-menu-item>
        <el-menu-item index="3" disabled>
          <i class="el-icon-document"></i>
          <span slot="title">導(dǎo)航三</span>
        </el-menu-item>
        <el-menu-item index="4">
          <i class="el-icon-setting"></i>
          <span slot="title">導(dǎo)航四</span>
        </el-menu-item>
      </el-menu>
    </el-col>
  </el-row>
</template>

<script>
export default {
};
</script>

<style scoped>
/*去掉最右邊的白框,個人習(xí)慣*/
.el-menu {
  border-right: 0;
}
</style>

Admin.vue

<el-aside width="300px"><Aside /></el-aside>
name: 'App',
  components: {
    Aside,
  },

修改下Admin.vue中的背景色,否則太難看

.el-aside {
  background-color: #545c64;/*這里*/
  color: #333;
  text-align: center;
}

現(xiàn)在,npm run dev,正常的話,顯示效果已經(jīng)出來了!
下面來實現(xiàn)動態(tài)效果。
現(xiàn)在修改Aside.vue來實現(xiàn)自定義菜單

<template>
  <el-row>
    <el-col :span="24">
      <h5>管理后臺</h5>
      <el-menu
        default-active="2"
        class="el-menu-vertical-demo"
        background-color="#545c64"
        text-color="#fff"
        active-text-color="#ffd04b">
        <template v-for="menu in menus">
        <el-submenu :index="menu.index" v-if="menu.items" :key="menu.index">
          <template slot="title"><i :class="getIcon(menu.icon)"></i>{{menu.label}}</template>
          <el-menu-item v-for="item in menu.items"
           :index="item.index" @click="send(item)" :key="item.index">
            <i :class="getIcon(item.icon)"></i>{{item.label}}
          </el-menu-item>
        </el-submenu>
        <el-menu-item :index="menu.index" @click="send(menu)" :key="menu.index" v-else>
          <i :class="getIcon(menu.icon)"></i>{{menu.label}}
        </el-menu-item>
      </template>
      </el-menu>
    </el-col>
  </el-row>
</template>

<script>
/**
 * 定義一個menus,體驗菜單的動態(tài)渲染
 * 將來會通過props傳進(jìn)來
 */
const menus = [
  {
    index: '1',
    label: '配置管理',
    icon: 'document',
    items: [
      {
        index: '11',
        label: '網(wǎng)站配置',
        url: 'web.json',
      },
      {
        index: '12',
        label: '數(shù)據(jù)庫配置',
        url: 'core,json',
      },
    ],
  },
  {
    index: '2',
    label: '用戶管理',
    url: 'login.json',
    redirect: true,
  },
  {
    index: '3',
    label: '統(tǒng)計信息',
    url: 'status.json',
    icon: 'location',
  },
];

export default {
  data() {
    return { menus };
  },
  methods: {
    send(item) {
      this.$emit('redirect', item);
    },
    getIcon(icon = 'menu') {
      return `el-icon-${icon}`;
    },
  },
};
</script>

<style scoped>
/*去掉菜單最右邊的白框,個人習(xí)慣*/
.el-menu {
  border-right: 0;
  text-align: left;
}
</style>

我們的菜單已經(jīng)是通過一個數(shù)組menus來自定義了,根據(jù)vue特性,修改menus菜單就會變化哦,現(xiàn)在我們先不測試這個,留待將來在測試。我們這個有更重要的,菜單點擊后會向Admin組件發(fā)布redirect消息,我們修改Admin組件,處理這個消息。
Admin組件添加響應(yīng)消息的地方

<el-aside width="240px"><Aside @redirect="onRedirect"/></el-aside>
...
<el-main><component :config="view" v-bind:is="view.name" /></el-main>
...
<script>
export default {
  data() {
    return {
      view: {
      },
    };
  },
  methods: {
    submit() {
      this.$emit('redirect', { url: '/login.json' });
    },
    onRedirect(action) {
      // 冒泡
      if (this.passUp(action)) return this.$emit('redirect', action);
      // 本地處理
      return this.$HttpSend(action).then((response) => {
        this.view = response.view;
        throw new Error('route');
      }).catch(() => {});
    },
    passUp(action) {
      return action && action.redirect;
    },
  },
};
</script>

Admin組件添加幾個臨時組件方便效果展示


const Table = {
  template: '<H1>Table</H1>',
};

const Form = {
  template: '<H1>Form</H1>',
};

const Chart = {
  template: '<H1>Chart</H1>',
};

export default {
  components: {
    Aside,
    Table,
    Form,
    Chart,
  },
data() {...

突發(fā)奇想,就想修改下Http.js(HttpSend參數(shù)格式變了)

/**
   * 遠(yuǎn)程調(diào)用的核心方法
   * @returns {Promise<T>}
   */
  static HttpSend = (action = {}) => {
    /** @type {boolean} */
    const withValue = action && action.value;
    const option = {
      url: Http.createUrl((action) ? action.url : undefined),
    };
    if (action && action.post) {
      option.method = 'post';
      if (withValue) option.data = Qs.stringify(action.value);
      option.headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
    } else {
      if (withValue) option.params = JSON.parse(JSON.stringify(action.value));
      option.method = 'get';
    }
    // 開啟跨域cookie
    option.withCredentials = true;
    option.paramsSerializer = params => Qs.stringify(params, { arrayFormat: 'brackets' });
    return $http(option).then((response) => {
      const data = response.data;
      // 判斷返回結(jié)果信息
      if ((function isError(v) {
        if (typeof v !== 'object') return false;
        if (v.status === false) return true;
        return (v.status && Number(v.status) <= 0);
      })(data)) return Http.onError(data, '操作無效');
      return Http.onReceive(data);
    }, error => Http.onError(error, '數(shù)據(jù)獲取失敗'))
      .catch(error => Http.onError(error, '內(nèi)部錯誤'));
  };

  /**
   * 觸發(fā)鉤子函數(shù)
   * @type {Function}
   * @param {Object}  data
   * @returns {Object}
   */
  static onReceive = (data) => {
    Http.receivers.forEach(receiver => receiver(data));
    return data;
  }

  /**
   * 插件安裝函數(shù)
   */
  static install(Vue) {
    this.vue = Vue;

    this.createUrl = this.vue.createUrl || (url => url);

    this.vue.prototype.$httpGet = (url, value = null) => this.HttpSend({ url, value });
    this.vue.prototype.$HttpPost = (url, value = null) => this.HttpSend({ url, value, post: true });
    this.vue.prototype.$HttpSend = Http.HttpSend;

    this.vue.prototype.$addReceiver = receiver => this.receivers.push(receiver);

    this.vue.prototype.$removeReceiver = id => this.receivers.splice(id, 1);
  }

看看神奇的效果吧。原來的幾個按鈕,因為Http.js的修改,失效了,改起來很簡單,不會就問我。

這樣呢,App和Admin有一部分重復(fù)的功能,我們提取出來

<script>
export default {
  data() {
    return {
      view: {
      },
    };
  },
  methods: {
    onRedirect(action) {
      // 冒泡
      if (this.passUp(action)) return this.$emit('redirect', action);
      // 本地處理
      return this.$HttpSend(action).then((response) => {
        this.view = response.view;
        throw new Error('route');
      }).catch(() => {});
    },
    passUp(action) {
      return action && action.redirect;
    },
  },
};
</script>

取名叫Container.vue放在components下。
修改App.vue

import Father from './components/Container';
...
export default {
  name: 'App',
  extends: Father,
  data() {
    return {
      trace: {
        rows: [],
      },
    };
  },
  ...
  methods: {
    passUp() {
      return false;
    },
  },
};
</script>

修改Admin.vue

export default {
  extends: Father,
   ...
  methods: {
    submit() {
      this.$emit('redirect', { url: '/login.json' });
    },
  },
};

看看效果,媽呀,組件繼承就這么簡單?。?!

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

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

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