本文源碼javascript
主要用到的技術:vue-cli + vue2 + vue-router2 + vuex2 + axios + es6 + sass + eslint
css
主要實現的功能:
頁面的數據經過 axios 模擬請求本地的 json 文件得到;
vue-router2 實現各頁面的相互跳轉;
vuex2 全局狀態的管理,如頭部導航的標題內容,側欄的顯示狀態;
簡易購物車功能,詳情頁加入購物車的商品,隨機生成單價、商品名字;
購物車的信息經過localstorage存儲在本地;
註冊登陸的信息也是經過localstorage存儲在本地。html
proj5-shop 目錄結構,主要看src目錄和static目錄的:vue
│--build |--config |--dist |--src |--assets |--logo.png |--components |--cart 購物車頁 |--cate 商品列表頁,商品詳情頁 |--center 我的中心,註冊登陸 |--com 公共模塊 |--header.vue 頭部 |--loading.vue 加載 |--sidebar.vue 導航側欄 |--swiper.vue 輪播 |--jam.js 公共功能函數 |--localDB.js localStorage本地存儲 |--page 首頁 |--Hello.vue |--static 本地數據模擬請求(需放static目錄下) |--data |--cart.json |--cate.json |--index.json | .gitkeep |--test │ .babelrc │ .editorconfig │ .eslintignore │ .eslintrc.js │ .gitignore │ index.html │ package.json │ README.md
vue-cli 腳手架官方安裝:https://github.com/vuejs-templates/webpackjava
$ npm install -g vue-cli $ vue init webpack proj5-shop $ cd proj5-shop $ npm install $ npm run dev
vue-cli初始化完成後,繼續新增安裝如下依賴:node
cnpm install axios node-sass vuex sass-loader vue-swipe --save-dev
修改 build/webpack.base.conf.js
,使其對import引入的sass支持:webpack
{ test: /\.vue$/, loader: 'vue-loader', options: vueLoaderConfig } // 將上面的修改爲下面的: { test: /\.vue$/, loader: 'vue-loader', options: { loaders: { 'scss': 'vue-style-loader!css-loader!sass-loader', 'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax' } } }
商品分類頁 src/components/cate/cate.vue
的 template:ios
<template> <div class="s-cate"> <div class="cate-nav"> <div class="nav-out"> <div class="nav"> <a class="nav-a" href="javascript:;" v-for="(type, index) in types" :class="{'nav-a-act': index==nowIndex}" @click="clickType(type.type_now, index)"> {{type.type_name}} </a> </div> </div> </div> <div class="cate-cont"> <ul> <li v-for="brand in allBrand" v-if="nowType==brand.type || nowType=='type_all'"> <router-link to="detail" class="cont-li" href="javascript:;"> <img class="pic" :src="brand.brand_pic_url"/> <span class="name">{{brand.brand_name}}</span> <span class="price">{{brand.brand_price}}</span> </router-link> </li> </ul> </div> </div> </template>
商品詳情頁 src/components/cate/detail.vue
的 template:git
<template> <div class="s-detail"> <comSwiper></comSwiper> <div class="cont"> <p class="name">{{detailData.cart_name}}</p> <span class="price">¥{{detailData.cart_price}}</span> <div class="goods-counter"> <a href="javascript:;" class="btn-sub" @click="changeNum(-1, detailData)"> - </a> <input type="text" class="goods-num" readonly="readonly" v-model="detailData.cart_num"> <a href="javascript:;" class="btn-add" @click="changeNum(1, detailData)"> + </a> </div> </div> <div class="bot"> <!-- <router-link class="add-cart" v-on:click.native="addCart" to="/cart">加入購物車</router-link> --> <a class="add-cart" href="javascript:;" @click="addCart">加入購物車</a> </div> </div> </template>
首頁的數據請求:
首先在入口文件 main.js
引入 axios,並將其掛在到 Vue 全局方法下:es6
// main.js import axios from 'axios' Vue.prototype.$http = axios
在首頁 page/index.vue
使用 axios:
<script> import comSwiper from '../com/swiper' import '../../css/index.scss' export default { // 首先聲明一些頁面數據變量 data () { return { dataIndex: {}, temai: {}, rexiao: {}, jingpin: {} } }, created () { // created的時候請求數據 this.getDataIndex() }, methods: { // 請求到數據並賦值給data裏聲明的變量 getDataIndex () { this.$http.get('../../static/data/index.json').then((response) => { this.dataIndex = response.data this.temai = this.dataIndex.data.temai this.rexiao = this.dataIndex.data.rexiao this.jingpin = this.dataIndex.data.jingpin }, (response) => { // error }) } } } </script>
最終將數據渲染在 template 上:
<div class="cont-main cont-rexiao"> <router-link to="/detail" class="cont-left" href="javascript:;" v-for="(brand, key, index) in rexiao" v-if="key==0" :key="brand.id"> <span class="name">{{brand.brand_name}}</span> <span class="desc">{{brand.brand_desc}}</span> <img class="pic" :src="brand.brand_pic_url"/> </router-link> <div class="cont-right"> <router-link to="/detail" class="cont-right-one" href="javascript:;" v-for="(brand, key, index) in rexiao" v-if="key>=1" :key="brand.id"> <p class="text"> <span class="name">{{brand.brand_name}}</span> <span class="desc">{{brand.brand_desc}}</span> </p> <img class="pic" :src="brand.brand_pic_url"/> </router-link> </div> </div>
router/router.js
路由:
import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter) import App from '../App.vue' import Index from '../components/page/index.vue' import Cate from '../components/cate/cate.vue' import Detail from '../components/cate/detail.vue' import Center from '../components/center/center.vue' import Cart from '../components/cart/cart.vue' export default new VueRouter({ routes: [ { path: '/', redirect: '/index', component: App, children: [ {path: 'index', name: 'index', component: Index}, {path: 'cate', name: 'cate', component: Cate}, {path: 'detail', name: 'detail', component: Detail}, {path: 'center', name: 'center', component: Center}, {path: 'cart', name: 'cart', component: Cart} ] } ], linkActiveClass: 'footer-act' })
主要是經過 router-link
來跳轉,好比導航欄 com/sidebar.vue
的跳轉:
<ul class="ul-nav" v-show="show"> <li><router-link to="/index"><span>首頁</span><i>></i></router-link></li> <li><router-link to="/cate"><span>分類</span><i>></i></router-link></li> <li><router-link to="/center"><span>個人</span><i>></i></router-link></li> <li><router-link to="/cart"><span>購物車</span><i>></i></router-link></li> </ul>
固然,在 加入購物車
的時候,採用的編程式導航跳轉路由:
<!-- <router-link class="add-cart" v-on:click.native="addCart" to="/cart">加入購物車</router-link> --> <a class="add-cart" href="javascript:;" @click="addCart">加入購物車</a> // 編程式導航,點擊時觸發路由跳轉 router.push({ path: 'cart' })
vuex 狀態管理主要是頭部的顯示信息、導航欄的顯示隱藏狀態:
先來看 store/store.js
:
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { sideBarState: false, //導航側欄的顯示狀態 headerTitle: '默認的頭部標題' //不一樣頁面頭部標題的變動 }, mutations: { changeSideBarState (state, boolean) { state.sideBarState = boolean }, changeHeaderTitle (state, str) { state.headerTitle = str } }, actions: { // changeSideBarState (context, status) { // context.commit('changeSideBarState', status) // } // es6解構寫法 changeSideBarState ({commit}, status) { commit('changeSideBarState', status) }, changeHeaderTitle ({commit}, str) { commit('changeHeaderTitle', str) } }, getters: { getSideBarState (state) { return state.sideBarState }, getHeaderTitle (state) { return state.headerTitle } } })
例如,在進入分類頁 cate/cate.vue
時,會在 created
的時候觸發頭部標題的變動;
當點擊頭部 導航
時,又會觸發導航側欄的顯示狀態的變動:
created () { this.$store.dispatch('changeHeaderTitle', '分類') }, methods: { showSideBar () { return this.$store.dispatch('changeSideBarState', true) // return this.$store.commit('changeSideBarState', true) }, hideSideBar () { return this.$store.dispatch('changeSideBarState', false) } }
在進入商品詳情頁的時,會隨機生成商品的名稱和價格,使得 加入購物車
時能在購物車頁面區分開個商品(主要是還沒作後端node+mongodb的數據):
// cate/detail.vue data () { return { detailData: { id: 100048, type: 'type_man', isSelect: true, cart_img: 'http://ohe5avf3y.bkt.clouddn.com/pro/vue/vue-shop/vue-proj-goods.jpg', cart_name: '商品名字' + this.getRandom(10, 100), cart_num: 1, cart_price: this.getRandom(10, 100) } } }
點擊 加入購物車
,實際就是將該商品的 data 信息加入到 localStorage 的本地存儲中;這裏主要用到一個本身定義的 localDB.js
:
export default class todoDb { constructor (name) { this.name = name if (JSON.stringify(this.get(this.name)) === '{}') { this.set([]) } } set (val) { window.localStorage.setItem(this.name, JSON.stringify(val)) } get () { return JSON.parse(window.localStorage.getItem(this.name)) || {} } }
購物車 cart/cart.vue
主要思路就是:讀取本地存儲購物車中的localStorage 全部產品信息並顯示出來;根據用戶增刪操做、來更新本地購物車存儲的產品信息。
具體的實現直接看 購物車源碼。
註冊登陸的用戶中心頁面 center/center.vue
,主要是控制三種狀態的顯示與隱藏:登陸、註冊、登陸成功後的用戶中心,主要是data裏面的 showState ;
還有就是表單數據的一些綁定驗證,主要是data裏面的 dataLogin 。
<input name="mobile" type="tel" placeholder="請輸入手機號" maxlength="11" v-model="dataLogin.name"> <input name="password" type="tel" placeholder="請輸入密碼" maxlength="6" v-model="dataLogin.pass"> <script> data () { return { tips: '', showState: 'logined', dataLogin: { name: '', pass: '', code: '' }, // showState: 'register' // showState: 'logining' } } </script>
詳情看github源碼中的 center/center.vue
。
build 後需在服務器打開訪問
執行 npm run build
後生成的dist,直接在瀏覽器以本地文件 file:// ... 打開裏面的index.html 、是訪問不了的;須要放在服務器上才能訪問;或者本身在本地開啓一個服務器。
引入的component,外層要有容器
以下面的 <comHeader></comHeader> ,它外層必定要有容器、把它包裹着:
<div class="shop"> <comHeader></comHeader> </div>
v-for key
component lists rendered with v-for should have explicit keys:
<router-link to="/detail" class="cont-one" v-for="brand in temai" :key="brand.id"> // ... </router-link>
詳見:https://cn.vuejs.org/v2/guide/list.html#key
原生html報waring
當咱們引入的component命名成原生的html時,會報warning,因而把
<hearder></header> // 報 warning <comHearder></comHeader> import comHeader from './components/com/header.vue' components: { // hearder: hearder comHeader: comHeader }
判斷對象爲空
if (typeof myObj == "undefined") { var myObj = {}; }
webstorm卡頓
webstorm 須要把 node_models 文件夾排除掉(exclued),否則很卡頓。
目前正學習node+mongodb,準備以此取代該項目中模擬的本地數據請求和localStorage,項目代碼:https://github.com/gjincai/vue-node-proj