記錄第一個vue項目——FlashPiggy后臺管理

項目概述

  • 對接小程序端:閃電豬——直達對象的定制化調研工具,實現超級管理員對商家、門店、項目、禮品、成就、用戶等信息的增刪改查管理,對門店項目數據統計并進行可視化分析。商家經授權后可在平臺上發布自定義市場調研任務,對門店項目、禮品庫、成就規則庫進行管理,查看門店項目數據等。
  • 技術棧:vue2.0 + bootstrap-vue + vue-cli + vue-router + axios + vue-axios + echarts
  • 項目地址:flashpiggy-admin
  • 運行:npm run serve

項目結構

├── dist/  #打包后的文件存放目錄
├── node_modules/ #模塊文件
├── src/ #項目入口目錄
    ├── assets/   #前端資源目錄(圖片)
    ├── components/   # vue組件目錄/.vue文件存放目錄
         ├─busi #總商管理組件目錄
             ├── business_extrabar.vue #總商管理副側邊欄組件
             ├── business_content.vue #總商信息主內容組件
             ├── permission_content.vue #權限配置主內容組件
             ├── achievement_content.vue #成就管理主內容組件
             ├── achi_content_detail.vue #成就詳情主內容組件
             ├── goods_content_detail.vue #禮品詳情主內容組件
             ├── business_table.vue #總商概述列表組件(點擊跳轉門店詳情)
             ├── achievement_table.vue #成就概述列表組件(點擊查看成就詳情)
             ├── goods_table.vue #禮品列表組件(點擊查看禮品詳情)
             ├── achi_table_detail.vue #成就詳情列表組件
             ├── goods_table_detail.vue #禮品詳情列表組件
         ├─project #項目管理組件目錄
             ├──project_extrabar.vue #項目管理副側邊欄組件 
             ├── shop_content.vue #門店主內容組件
             ├── project_content.vue #項目主內容組件
             ├── mission_content.vue #任務主內容組件
             ├── question_content.vue #問卷主內容組件
             ├── answer_content.vue #答案主內容組件
             ├── shop_table.vue #門店列表組件
             ├── project_table.vue #項目列表組件
             ├── mission_table.vue #任務列表組件
             ├── question_table.vue #問卷列表組件
             ├── answer_table.vue #答案列表組件
             ├── project_data_detail.vue #項目管理->門店項目詳情組件
             ├── project_data_analyse.vue  #項目數據圖表分析組件
         ├─reuse #重用組件目錄 
             ├── layout.vue #總布局組件
             ├── login.vue #登陸組件
             ├── sidebar.vue #側邊欄組件
             ├── XPopLayer.vue #彈出層組件
         └─user #用戶管理組件目錄
             ├── user_extrabar.vue #用戶管理副側邊欄組件
             ├── user_content.vue #用戶信息主內容組件
             ├── user_table.vue #用戶信息列表組件
             ├── user_table_detail.vue #用戶詳情列表組件
         ├─setting #系統設置組件目錄
    ├── App.vue # 項目根組件
    ├── main.js # 項目入口文件(vue路由管理)
├── package.json #包文件信息
├── babel.config.js
├── .gitignore
├── README.md

項目小記

寫這篇文章很倉促,先暫時搬運做這個項目時的筆記,之后再慢慢整理。

一、路由導航
1.聲明式導航:使用 <router-link> 創建<a>標簽來定義導航鏈接
<router-link to="/achievement_info">獎勵成就</router-link>
  • 點擊 <router-link> 時,這個方法會在內部調用,所以說,點擊 <router-link to="..."> 等同于調用 router.push(...)。
  • Tips:如果在同一個父組件下使用router-link切換子組件,子組件不會重新掛載(掛載鉤子函數mouted()不會執行),若想子組件重新掛載,可給子組件加上一個key值標識。
2.編程式導航:使用router.push 方法
  this.$router.push({path:"/shop_info", query: {business_code:row.userCode}});
  • 這個方法會向 history 棧添加一個新的記錄,所以,當用戶點擊瀏覽器后退按鈕時,則回到之前的 URL
  • 該方法的參數可以是一個字符串路徑,或者一個描述地址的對象。例如:
// 字符串                                                               
router.push('home')                                                                                                                  
// 對象                         
router.push({ path: 'home' })                  
// 命名的路由           
router.push({ name: 'user', params: { userId: 123 }})    
// 帶查詢參數,變成 /register?plan=private            
router.push({ path: 'register', query: { plan: 'private' }})

  • Tips:獲取參數,this.$route.query.plan -> private
  • 如果提供了 path,params 會被忽略,上述例子中的 query 并不屬于這種情況。
    取而代之的是下面例子的做法,需要提供路由的 name 或手寫完整的帶有參數的 path:
const userId = 123                                                                  
router.push({ name: 'user', params: { userId }}) // -> /user/123    
router.push({ path: `/user/${userId}` }) // -> /user/123               
// 這里的 params 不生效                                                          
router.push({ path: '/user', params: { userId }}) // -> /user 

同樣的規則也適用于 router-link 組件的 to 屬性。

二、Vue組件
1.局部注冊組件
import TheSidebar from "./components/reuse/sidebar.vue";
import Layout from "./components/reuse/layout.vue";
export default {
  name: "app",
  components: {
    'TheSidebar': TheSidebar,
    'Layout': Layout
  }
};
2.使用組件
<template>
  <div id="app">
    <layout /> 
    <TheSidebar />
  </div>
</template>
3.動態組件
  • 使用 is 特性來切換不同的組件并使用<keep-alive>緩存組件狀態,避免反復重渲染導致的性能問題。

    <div id="l-main-list-wrap">
            <div class="l-main-tab" >
                <div
                    class="tab"
                    v-for="(value, index) in operations"
                    @click="toggleTab(value.key,index)"
                >
                    <a :class="{ui_on:index===isActive}">{{value.label}}</a>
                </div>
            </div>
            <div class="l-main-tabCon">
                <goods_table :is="currentTab" :opfields="current_fields" :urls="current_urls" keep-alive></goods_table>
            </div>
    </div>

三、BoostrapVue表格組件

[圖片上傳失敗...(image-5d80d6-1577449037174)]

<template>
   <b-table show-empty
      :hover="hover"
      :striped="striped"
       stacked="md"
       :items="items"
       :fields="fields"
       :current-page="currentPage"
       :per-page="perPage"
       :filter="filter"
       :sort-by.sync="sortBy" 
       :sort-desc.sync="sortDesc"
       :sort-direction="sortDirection"
       @filtered="onFiltered"
       @row-clicked="rowClick"
   >    
   <template slot="name" slot-scope="row">{{row.value}}</template>
   <template slot="actions" slot-scope="row">
     <b-button size="sm" class="mr-1" @click="showOverlay(row.index+ ( currentPage - 1 ) * 5)">修改</b-button>
     <b-button size="sm" data-toggle="modal" data-target="#layer" @click="deleteMsg(row.index+ ( currentPage - 1 ) * 5)">刪除</b-button>
   </template>
   </b-table>
</template>
<script>
    const items = [
  {   
    business_name: "星巴克",
    business_code:"1001",
    exchange_num: 2,
    sum: 5,
    num: 2,
  },
  {    
    business_name: "資生堂",
    business_code:"1010",
    exchange_num: 2,
    sum: 5,
    num: 2,
  }
];
export default {
  data() {
    return {
      hover: true,
      striped:true,
      items: items,
      selectedlist: {},
      selected: -1,
      isShow: false,
      currentPage: 1,
      perPage: 5,
      totalRows: items.length,
      sortBy: null,
      sortDesc: false,
      sortDirection: "asc",
      filter: null
    };
  },
    props:['opfields','urls'],
    computed: {
        fields :function(){
            // this.searchAll();
            return this.opfields;
        },
    sortOptions() {
      // Create an options list from our fields
      return this.opfields.filter(f => f.sortable).map(f => {
        return { text: f.label, value: f.key };
      });
    }
</script>
四、表格數據增刪改查
1.以項目列表project_table為例
  • 根據isShow判斷是否顯示
<template>
<!-- selectedlist用來暫存彈層數據 -->
 <XPopLayer :list="selectedlist" :fields="fields" v-show="isShow" @updateShow="updateTheModelShow" @modify="modify" ></XPopLayer>
<div class="main-icon main-icon_add" @click="toggleAdd()"></div>
<b-button size="sm" class="mr-1" @click="showOverlay(row.index+ ( currentPage - 1 ) * 5)">修改</b-button>
<b-button size="sm" data-toggle="modal" data-target="#layer" @click="deleteMsg(row.index+ ( currentPage - 1 ) * 5)">刪除</b-button>
</tempalte>   

<script>
    //新增按鈕
    toggleAdd: function() {
      this.isShow = !this.isShow;  //isShow在data里設為false
    },
    //修改按鈕
    showOverlay(index) {
      this.selected = index;     //selected在data里設為-1
      this.selectedlist = this.items[index];
      this.toggleAdd();
    },
    //刪除按鈕
    deleteMsg: function(n) {
      this.items.splice(n, 1);
    },
</script>

2.彈層組件內容
  • 根據fieldsType判斷表單輸入框類型:默認普通文本框, 文本域框,單選框,復選框,文件輸入框等
<tempalte>   
//關閉按鈕
   <i class="main-icon main-icon_close" @click="close()"></i>  

//PopLayer的內容
 <div class="add-business_main">
                    <div v-for="value in modifyfields" :key="value.id">
                      <b-row v-if="!value.hasOwnProperty('isshow')||value.isshow">
                        <b-col md="3"> <label>{{value.label}}</label></b-col>
                        <b-col md="6" v-if="value.hasOwnProperty('fieldsType')&&value.fieldsType==='select'">
                          <b-form-select size="sm" v-model="modifylist[value.key]">
                            <option v-for="option in value.fieldsOptions" :value="option.value" :key="option.id">{{option.text}}</option>
                          </b-form-select>             
                        </b-col>
                        <b-col md="6" v-else-if="value.hasOwnProperty('fieldsType')&&value.fieldsType==='textarea'">
                          <b-form-textarea v-model="modifylist[value.key]" :rows="3"
                                           :max-rows="6"></b-form-textarea>
                        </b-col>
                        <b-col md="6" v-else-if="value.hasOwnProperty('fieldsType')&&value.fieldsType==='checkbox'">
                          <b-form-checkbox-group  id="checkboxes1" v-model="selected"  :options="value.fieldsOptions"></b-form-checkbox-group>
                        </b-col>
                        <b-col md="6" v-else-if="value.hasOwnProperty('fieldsType')&&value.fieldsType==='fileinput'">
                          <b-form-file accept=".jpg, .png, .gif" v-model="file" :state="Boolean(file)" placeholder="請選擇圖片"></b-form-file>
                        </b-col>
                        <b-col md="6" v-else>
                          <b-form-input size="sm" v-model="modifylist[value.key]"></b-form-input>
                        </b-col>
                        <br>
                      </b-row>
                    </div>

//提交按鈕
<b-col md="3" offset-md="5"><b-button size="md" @click="modify()">提交</b-button></b-col>
</tempalte>   

3.父子組件之間通信
  • 這里使用組件自定義事件,子組件冒泡觸發父組件的方法。

vm.$emit( eventName, […args] )

觸發當前實例上的事件。附加參數都會傳給監聽器回調。

<script>
    //關閉總商彈層
    close: function() {
      this.$emit("updateShow", false);      
    },
    //提交按鈕
    modify: function() {
      this.$emit("modify", this.modifylist);
    }
</script>

父組件以project_table.vue為例:

Vue.set( target, key, value )

向響應式對象中添加一個屬性,并確保這個新屬性同樣是響應式的,且觸發視圖更新。它必須用于向響應式對象上添加新屬性,因為 Vue 無法探測普通的新增屬性
(比如 this.myObject.newProperty = 'hi')

arrayObject.push(newelement1,newelement2,....,newelementX)

  • push() 方法可向數組的末尾添加一個或多個元素,并返回新的長度。
    push() 方法可把它的參數順序添加到 arrayObject 的尾部。它直接修改 arrayObject,而不是創建一個新的數組。push() 方法和 pop() 方法使用數組提供的先進后出棧的功能。
<script>
    //子組件提交按鈕冒泡觸發
    modify(arr) {
      if (this.selected > -1) {  
  //修改->提交          點擊修改時,selected值取的是index(0,1,2...),必定>-1
      this.$set(this.items, this.selected, arr);    //這是全局 Vue.set 的別名
        this.selected = -1;      //重置selected為-1
      } else {
        this.items.push(arr);     //-1表示點擊順序為新增->提交
      }
      this.toggleAdd();
    },
    updateTheModelShow(s) {
      this.isShow = s;
    },
</script>
五、Axios

留個坑

六、CSS3簡單圖片輪播
1.CSS3 動畫屬性(Animation)
說明
animation-name 指定要綁定到選擇器的關鍵幀的名稱
animation-duration 動畫指定需要多少秒或毫秒完成
animation-timing-function 設置動畫將如何完成一個周期
animation-delay 設置動畫在啟動前的延遲間隔。
animation-iteration-count 定義動畫的播放次數。
animation-direction 指定是否應該輪流反向播放動畫。
animation-fill-mode 規定當動畫不播放時(當動畫完成時,或當動畫有一個延遲未開始播放時),要應用到元素的樣式。
animation-play-state 指定動畫是否正在運行或已暫停。
initial 設置屬性為其默認值。
inherit 從父元素繼承屬性。
2.基本思路
  • 基本布局
    將5張圖片左浮動橫向并排放入一個div容器(#photos)內,圖片設置統一尺寸,div寬度設置5個圖片的總尺寸,然后放入相框容器div(#frame),相框設置1個圖片的大小并設置溢出隱藏,以保證正確顯示一個照片。
  • 設置動畫
    然后使用css3動畫,通過對photos進行位移,從而達到顯示不同的圖片,每次偏移一個圖片的寬度,即可顯示下一張圖片。5張圖片,需要切換4次,定義動畫0%,20%,40%,80%,100%。
  • 動畫分解
    為了讓圖片切換后靜置一段時間,可以將動畫細分為:位移切換和靜置兩個階段。即20%~40%里面包含切換到第二張圖片并且將第二張圖片靜置。另外,根據需要可以對各個圖片添加相應的序號和圖片簡介。
  • 其他事件
    如果需要點擊事件的話,配合js完成其他特效(如:點擊序號顯示相應的圖片、上一張下一張等)
<div class="slide" v-on:mouseover="stop()" v-on:mouseout="move()">
  <div class="slideshow">
    <transition-group tag="ul" name="image">
      <li v-for="(img, index) in imgArray" :key="index" v-show="index === mark">
        <a href="">
        <img :src='img'>
        </a>
      </li>
    </transition-group>
  </div>
   <div class="bar">
     <span v-for="(item, index) in imgArray" :key="index"
        :class="{'active':index === mark}" @click="change(index)"></span>
   </div>
</div>
/* 圖片輪播 */
.slide {
    width: 300px;
    height: 200px;
    overflow: hidden;
    position: relative;
}

.slideshow {
    width: 300px;
    height: 200px;
}
.slideshow li {
    position: absolute;
}
.slideshow img {
    width: 300px;
    height: 200px;
}
.bar {
    position: absolute;
    width: 100%;
    bottom: 10px;
    margin: 0 auto;
    z-index: 10;
    text-align: center;
  }
  .bar span {
    width: 20px;
    height: 5px;
    background: white;
    display: inline-block;
    margin-right: 10px;
    border-radius: 5px;
  }
  .active {
    background: #009aff !important;
  }
.image-enter-active {
    transform: translateX(0%);
    transition: all 1.5s ease;
}
.image-leave-active {
    transform: translateX(-100%);
    transition: all 1.5s ease;
}
.image-enter {
    transform: translateX(100%);
}
.image-leave {
    transform: translateX(0%);
}
七、使用Echarts圖表組件

待續

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 計算屬性 監聽 methods 里面用來設置方法 在模板得表達式里使用這個方法 '{{}}' 雙向數據綁定 v-m...
    web前端學習小白閱讀 329評論 0 1
  • vue-cli搭建項目 確保安裝了node與npm 再目標文件夾下打開終端 執行cnpm i vue-cli -g...
    Akiko_秋子閱讀 3,273評論 1 22
  • 1.css只在當前組件起作用答:在style標簽中寫入scoped即可 例如: 2.v-if 和 v-show 區...
    小棋子js閱讀 532評論 0 0
  • 一路上風雨不斷 濺起的水花把車窗覆蓋 偶爾一道閃光伴隨著雷聲 讓我有點緊張 放慢了車速一直往前 漸漸地雨勢變小了 ...
    梁可妮閱讀 116評論 0 0
  • 這個題目不好寫啊!自己已經過了盲目崇拜的年齡了,那寫誰呢?想了快一天突然想到應該寫寫我的老師! “...
    強哥_d8c3閱讀 361評論 0 0