項目概述
- 對接小程序端:閃電豬——直達對象的定制化調研工具,實現超級管理員對商家、門店、項目、禮品、成就、用戶等信息的增刪改查管理,對門店項目數據統計并進行可視化分析。商家經授權后可在平臺上發布自定義市場調研任務,對門店項目、禮品庫、成就規則庫進行管理,查看門店項目數據等。
- 技術棧: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.父子組件之間通信
- 這里使用組件自定義事件,子組件冒泡觸發父組件的方法。
觸發當前實例上的事件。附加參數都會傳給監聽器回調。
<script>
//關閉總商彈層
close: function() {
this.$emit("updateShow", false);
},
//提交按鈕
modify: function() {
this.$emit("modify", this.modifylist);
}
</script>
父組件以project_table.vue為例:
向響應式對象中添加一個屬性,并確保這個新屬性同樣是響應式的,且觸發視圖更新。它必須用于向響應式對象上添加新屬性,因為 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圖表組件
待續