天天看點

小米商城 -- vue項目實戰後端連接配接已不可用,該項目無效!

後端連接配接已不可用,該項目無效!

想看看前端代碼還是可以接着閱讀!

github: 小米商城源碼

賬号:sunyu    密碼:123456

       該項目是對小米商城系統的模仿,實作了從浏覽商品到結算商品的整個過程,其中包括了商品清單、根據價格篩選商品、對商品 排序、登入、加入購物車、結算等功能 前台使用vue-cli建構了請求伺服器,使用了Vue架構,還使用了vue-router、axios、Vuex等中間件 背景使用了node.js,express架構建構了背景伺服器

1.  項目初始化

全局環境下安裝vue,vue-cli 腳手架

npm install vue -g
npm install vue-cli -g           

初始化項目:

$ vue init webpack MiMall

? Project name (MiMall) mistore
? Project name mistore
? Project description (A Vue.js project) xiaomi store with vue
? Project description xiaomi store with vue
? Author (Spock <[email protected]>)
? Author Spock <[email protected]>
? Vue build (Use arrow keys)
? Vue build standalone
? Install vue-router? (Y/n)
? Install vue-router? Yes
? Use ESLint to lint your code? (Y/n) n
? Use ESLint to lint your code? No
? Set up unit tests (Y/n) n
? Set up unit tests No
? Setup e2e tests with Nightwatch? (Y/n) n
? Setup e2e tests with Nightwatch? No
? Should we run `npm install` for you after the project has been created? (recom
? Should we run `npm install` for you after the project has been created? (recom
mended) npm
           

先安裝幾個插件:

npm i babel-runtime fastclick babel-polyfill           

    "babel-polyfill": "^6.26.0",//es6的API轉義

    "babel-runtime": "^6.26.0",//對es6的文法進行轉義

    "fastclick": "^1.0.6",//解決移動端300ms延遲的問題

main.js中的設定:

import 'babel-polyfill'
import fastclick from 'fastclick'

fastclick.attach(document.body)//這樣就能解決body下按鈕點選300ms的延遲
           

2. 配置路由

   先配置路徑别名:(    // 别名,隻針對于js庫,css的引入還是要寫相對路徑,不能省略)

build/webpack.base.conf.js:

alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
      'components': resolve('src/components'), 
       //當在js檔案中import其他檔案時路徑直接寫commont相當于../src/components
      'api': resolve('src/api')   //後面會用到
    }           

src/router : 

配置别名的好處就在下面import的時候展現出來了。

先配置首頁,購物車,及位址欄的路由。

import Vue from 'vue'
import Router from 'vue-router'
import Goods from 'components/goods'
import Car from 'components/car'
import Address from 'components/address'

Vue.use(Router)

export default new Router ({
  routes: [
  {
    path: '/',
    component: Goods
  },
  {
    path: '/car',
    component: Car
  },
  {
    path: '/address',
    component: Address
  }
  ]
})
           

回到首頁面配置顯示的資訊:

src/App.vue: 

<template>
  <div id="app">
    <m-header></m-header>
    <tab></tab>
    <keep-alive>
      <router-view></router-view>
    </keep-alive>
  </div>
</template>

<script>
import MHeader from 'components/m-header'
import Tab from 'components/tab'

export default {
  components: {
    MHeader,
    Tab
  }
}
</script>

<style>
</style>
           

可以看到引用了幾個元件,還未建立。接下來建立這幾個頁面:

src/ components/goods.vue  (示例:car.vue,address.vue,m-header.vue,tab.vue也類似該結建構立)

<template>
<p>商品頁面</p>
</template>

<script>

</script>
<style type="text/css">

</style>
           

現在 控制台 輸入指令: npm run dev , 打開localhost:8080 就可以看到首頁面的資訊了。

3.   “Sticky Footer”布局:

  指的就是一種網頁效果: 如果頁面内容不足夠長時,頁腳固定在浏覽器視窗的底部;如果内容足夠長時,頁腳固定在頁面的最底部。但如果網頁内容不夠長,置底的頁腳就會保持在浏覽器視窗底部。

src/ components/footer.vue:

<template>
<div class="footer">
  <div class="footer-contain">
    <div class="area-select">
      <span>地區:</span>
      <select>
        <option value="中國">中國</option>
        <option value="USA">USA</option>
        <option value="India">India</option>
      </select>
    </div>
    <ul>
      <li>隐私政策</li>
      <li>團隊合作</li>
      <li>關于我們</li>
      <li>&copy;2018 taoMall.com 版權所有</li>
    </ul>
  </div>
</div>
</template>

<script>

</script>
<style type="text/css">
.footer {
  margin-top: -100px;
  width: 100%;
  height: 100px;
  background-color: #bbb;
  overflow: hidden;
}
.footer-contain {
  padding:0 120px;
  height: 100%;
  width: 100%;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.footer-contain .area-select {
  flex-width: 200px;
  width: 200px;
}
.footer-contain ul {
  display: flex;
}
.footer-contain ul li {
  margin-left: 10px;
}
</style>
           

然後更改App.vue中的内容:

<template>
  <div id="app">
    <div class="content-wrap">
      <div class="content">
        <m-header></m-header>
        <tab></tab>
        <keep-alive>
          <router-view></router-view>
        </keep-alive>
      </div>
    </div>
    <m-footer></m-footer>
  </div>
</template>

<script>
import MHeader from 'components/m-header'
import Tab from 'components/tab'
import Footer from 'components/footer'

export default {
  components: {
    MHeader,
    Tab,
    MFooter:Footer,
  }
}
</script>

<style>
#app {
  height: 100%;
}
.content-wrap {
  min-height: 100%;
}
.content {
  padding-bottom: 100px;
}
</style>
           

(缺點: 添加了兩個div标簽)

done!    ✿✿ヽ(°▽°)ノ✿

4. 根據路由位址顯示不同的文本資訊

src/components/tab.vue:  利用計算屬性及this.$route.path 得到路由位址

<template>
<div class="tab">
  <ul class="tab-contain">
    <li class="tab-item"><router-link  tag="a" to="/">首頁</router-link></li>
    <li class="tab-item"><span>{{tabTitle}}</span></li>
  </ul>
</div>
</template>

<script>
export default {
  data() {
    return {
      pathMap: {
        '/': '商品資訊',
        '/car': '購物車資訊',
        '/address': '位址資訊',
      }
    }
  },
  //計算屬性:邏輯計算,根據pathMap資料中的位址綁定顯示的文字
  computed: {
    tabTitle() {
      return this.pathMap[this.$route.path]
    }
  }
}
</script>
<style type="text/css">
 .tab {
  padding: 20px 100px;
  box-sizing: border-box;
  background-color: #f3f0f0;
 }
 .tab-contain {
  font-size: 0;
 }
 .tab-contain .tab-item {
  display: inline-block;
  font-size: 18px;
  margin-right: 10px;
 }
 .tab-contain .tab-item span {
  margin-left:10px;
  color: #de1442;
}
</style>
           

5.  利用axios擷取資料

(ps: 本打算利用axios僞造referer擷取資料,伺服器原api擷取有困惑,遂敗。直接設定跨域處理)

在前端 good.js 請求位址,不是直接請求服務端,而是請求我們自己的server端,然後我們的位址再去請求服務端(使用axios發送http請求)

下載下傳axios:

npm install axios --save           

src/api/goods.js:

import axios from 'axios'

export function getGoodsList() {
  const url = '/goods/list'

  const data = {
    page: 0,
    pageSize: 8,
    orderFlag: true,
    priceLeave: 'All'
  }

  return axios.get(url, {
    params:data
  }).then((res) => {
    return Promise.resolve(res)
  })
}
           

config/index.js:(設定跨域請求)

proxyTable: {
  '/goods/list': {
      target: 'http://linyijiu.cn:3000',
      changeOrigin: true
    }
  },
           

src/components/goods.vue:(請求資料)

<template>
<p>商品頁面</p>
</template>

<script>
import {getGoodsList} from 'api/goods'

export default {
  data() {
    return {
      goods : {}
    }
  },
  created() {
    this._getGoodsList()
  },
  methods: {
    _getGoodsList() {
      getGoodsList().then((res) => {
        this.goods = res.data
        console.log(this.goods)
      })
    }
  }
}

</script>
<style type="text/css">

</style>
           

重新啟動npm run dev,就能夠在控制台看到輸出的資料。

6.  實作商品頁面資料運用

src/compnents/goods.vue : 樣式還是用stylu寫比較好啊(´థ౪థ)σ

<template>
<div class="goods-contain">
  <div class="goods-sort">
    <p>排序:</p>
    <p>預設</p>
    <p class="goods-price">價格<span class="icon-arrow">↑</span></p>
  </div>
  <div class="goods-items">
    <ul class="price-inter">
      <li class="price-name">價格:</li>
      <li class="price-item active">全部</li>
      <li class="price-item" v-for="(item, index) in price">{{item.startPrice}}-{{item.endPrice}}</li>
    </ul>
    <ul class="goods-info">
      <li class="goods-des" v-for="(item, index) in goods" :key="index">
        <div class="good-all">
          <div class="good-image">
            <img :src="'/static/images/' + item.productImg">
          </div>
          <p class="good-name">{{item.productName}}</p>
          <p class="good-price">¥{{item.productPrice}}</p>
          <div class="add-car">加入購物車</div>
        </div>
      </li>
    </ul>
  </div>
</div>
</template>

<script>
import {getGoodsList} from 'api/goods'

export default {
  data() {
    return {
      goods : [],
      price:[
        {
          "startPrice":"0.00",
          "endPrice":"100.00"
        },
        {
          "startPrice":"100.00",
          "endPrice":"500.00"
        },
        {
          "startPrice":"500.00",
          "endPrice":"1000.00"
        },
        {
          "startPrice":"1000.00",
          "endPrice":"8000.00"
        },
      ],
    }
  },
  created() {
    this._getGoodsList()
  },
  methods: {
    _getGoodsList() {
      getGoodsList().then((res) => {
        this.goods = res.data
        console.log(this.goods)
      })
    }
  }
}

</script>
<style type="text/css">

</style>
           

7.  圖檔懶加載

安裝插件:

npm i vue-lazyload           

main.js 中引入:(先在static位址中放入圖檔資源)

import VueLazyLoad from 'vue-lazyload'

Vue.use(VueLazyLoad,{
  loading: '/static/images/Loading/loading-balls.svg'
})
           

src/components/goods.vue :   在圖檔的使用位址上更改為 v-lazy 即可。

<div class="good-image">
   <img v-lazy="'/static/images/' + item.productImg">
</div>
           

這下重新整理頁面就能夠看到有滾動的小球的加載過程。

8.   價格排序

邏輯:通過觀察 Headers

通過點選左邊不同區間的價格發現: priceLevel 控制顯示區間(全部時為all,其他時候為0,1,2,3)

通過點選價格排序發現:orderPrice升序為true,降序為false。

page 應該是拿來實作下拉加載圖檔的優化。

實作:是以這些參數應該在傳遞的時候變化,是以需要修改api請求的參數

src/api/goods.js: (将axios請求分離出來,不會讓頁面顯得冗長)

import axios from 'axios'

export function getGoodsList(page, pageSize,orderFlag,priceLevel) {
  const url = '/goods/list'

  const data = {
    page,
    pageSize,
    orderFlag,
    priceLevel
  }

  return axios.get(url, {
    params:data
  }).then((res) => {
    return Promise.resolve(res)
  })
}
           

src/components/goods.vue: 

<template>
<div class="goods-contain">
  <div class="goods-sort">
    <p>排序:</p>
    <p>預設</p>
    <p class="goods-price" @click="sortBy()">價格<span class="icon-arrow" :class="{arrow_turn:!orderFlag}">↑</span></p>
  </div>
  <div class="goods-items">
    <ul class="price-inter">
      <li class="price-name">價格:</li>
      <li class="price-item" :class="{active: priceLevel === 'all'}" @click="selectInter('all')">全部</li>
      <li class="price-item" :class="{active: priceLevel === index}" v-for="(item, index) in price" @click="selectInter(index)">{{item.startPrice}}-{{item.endPrice}}</li>
    </ul>
    <ul class="goods-info">
      <li class="goods-des" v-for="(item, index) in goods" :key="index">
        <div class="good-all">
          <div class="good-image">
            <img v-lazy="'/static/images/' + item.productImg">
          </div>
          <p class="good-name">{{item.productName}}</p>
          <p class="good-price">¥{{item.productPrice}}</p>
          <div class="add-car">加入購物車</div>
        </div>
      </li>
    </ul>
  </div>
</div>
</template>

<script>
import {getGoodsList} from 'api/goods'

export default {
  data() {
    return {
      goods : [],
      price:[
        {
          "startPrice":"0.00",
          "endPrice":"100.00"
        },
        {
          "startPrice":"100.00",
          "endPrice":"500.00"
        },
        {
          "startPrice":"500.00",
          "endPrice":"1000.00"
        },
        {
          "startPrice":"1000.00",
          "endPrice":"8000.00"
        },
      ],
      page: 0,        //下拉加載
      pageSize: 8,        
      orderFlag: true,    //升序還是降序
      priceLevel: 'all',  //顯示的區間
    }
  },
  created() {
    this._getGoodsList()
  },
  methods: {
    _getGoodsList() {
      getGoodsList(this.page, this.pageSize, this.orderFlag, this.priceLevel).then((res) => {
          this.goods = res.data  //得到商品清單資料存在goods變量中
      })
    },
    sortBy() {
      this.orderFlag = !this.orderFlag
      this.page = 0
      this._getGoodsList(false)
    },
    selectInter(index) {
      this.priceLevel = index
      this.page = 0
      this._getGoodsList(false)
    }
  }
}

</script>
<style type="text/css">
//
</style>
           

9.  下拉加載

建議看過此文再接着學習: vue 元件實作下拉加載

下載下傳元件:

npm install vue-infinite-scroll --save           

main.js : 全局環境下設定

import InfiniteScroll from 'vue-infinite-scroll'

Vue.use(InfiniteScroll)
           

api/ components/ goods.vue:

<template>
    <div v-infinite-scroll="loadMore" infinite-scroll-disabled="busy" infinite-scroll-distance="30">
    <!-- 加載更多 -->
    </div>
</template>

<script>
export default {
  data() {
    return {
      busy: false,
   }
 },
  mounted() {      //将擷取資料的函數放在mounted中執行是為了能夠在重新整理的時候也得到資料
    this._getGoodsList(false)
  },
 methods: {
    _getGoodsList(flag) {
      getGoodsList(this.page, this.pageSize, this.orderFlag, this.priceLevel).then((res) => {
        if (flag) {
          //多次加載資料,則需要把資料相加
          this.goods = this.goods.concat(res.data)
          if (res.data.length === 0) {
            //沒有資料可加載就關閉無限滾動
            this.busy = true
          } else {
            //否則仍可以觸發無限滾動
            this.busy = false
          }
        } else {
          //第一次加載資料并且允許滾動
          this.goods = res.data
          this.busy = false
        }
      })
    },
    loadMore() {
      this.busy = true
      //0.3s 後加載下一頁的資料
      setTimeout(() => {
        this.page ++
        this._getGoodsList(true)  //滾動的時候調用axios加載資料,參數判斷不是第一次加載
        }, 300)
    }
  }
}
</script>           

10. 登入頁面

邏輯: 點選登入後,顯示登入視窗,如果資訊正确則顯示登入後的資訊。是以添加一個事件showLogin() 控制視窗的登入。

<template>
    <div class="sign">
        <p class="signin" v-if="showLoginOut" @click = "showLogin()">登入</p>
        <div class="signout" v-if="!showLoginOut">
          <span class="sign-name"></span>
          <span class="sign-out">退出</span>
          <router-link to="/car" class="sign-car">購物車</router-link>
        </div>
    </div>
  </div>
</template>
<script>
import axios from 'axios'

export default {
  data() {
    return {
      showLoginOut : true,
    }
  },
  methods: {

    // 顯示登入視窗
    showLogin() {
      this.showLogDialog = true
    }
  }
</script>
           

       看了兩眼登入頁面,其實可以寫成一個子元件的形式,用于登入、注冊等的載體(沒有注冊頁啊!!!(ノ`Д)ノ   ),然後利用插槽插入基本內容。(運用了元件之間的參數傳遞)

建立一個基礎元件:

src/components/base/dialog.vue:

<template>
  <!-- 設計彈窗的架構樣式,再利用slot插槽插進不同的内容 -->
  <div>
    <div class="dialog-wrap" v-if="isShow">
        <div class="dialog-cover" @click="closeMyself"></div>
<!-- 動畫效果 -->
        <transition name="drop">
        <div class="dialog-content" v-if="isShow">
          <p class="dialog-close" @click="closeMyself">X</p>
          <!-- 插槽的位置 -->
          <slot>hello</slot>
        </div>
      </transition>

    </div>
  </div>
</template>

<script>
export default {
  props:{
    isShow:{
      type:Boolean,
      default:false
    }
  },
  methods:{
    closeMyself(){
      this.$emit('on-close')  //發送給父元件處理
    }
  }
};
</script>



<style scoped>
.drop-enter-active {
  transition: all .5s ease;
}
.drop-leave-active {
  transition: all .3s ease;
}
.drop-enter {
  transform: translateY(-500px);
}
.drop-leave-active {
  transform: translateY(-500px);
}

.dialog-wrap {
  position: fixed;
  width: 100%;
  height: 100%;
}
.dialog-cover {
  background: #000;
  opacity: .3;
  position: fixed;
  z-index: 5;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
.dialog-content {
  width: 50%;
  position: fixed;
  max-height: 50%;
  overflow: auto;
  background: #fff;
  top: 20%;
  left: 50%;
  margin-left: -25%;
  z-index: 10;
  border: 2px solid #464068;
  padding: 2%;
  line-height: 1.6;
}
.dialog-close {
  position: absolute;
  right: 5px;
  top: 5px;
  width: 20px;
  height: 20px;
  text-align: center;
  cursor: pointer;
}
.dialog-close:hover {
  color: #4fc08d;
}
</style>
           

在頭部引用:

src/components/m-header.vue:(父元件傳遞值給子元件,并且處理子元件傳遞來的事件)

<template>
  <my-dialog :is-show="showLogDialog" @on-close="closeDialog('showLogDialog')">
    <!-- my-dialog 插件控制彈窗,父元件綁定is-show屬性傳遞給子元件,并且根據值判斷彈窗是否展示 -->
  </my-dialog>

</template>

<script>
import Dialog from './base/dialog'

export default {
  data() {
    return {
      showLogDialog: false //該變量控制視窗是否顯示
    }
  },
  methods: {
    closeDialog(attr) {
      this[attr] = false
    },
    showLogin() {
      this.showLogDialog = true
    }
  },
  components: {
    MyDialog: Dialog // 名稱
  }
}
</script>
           

然後填充插槽内容即可。

11. 往插槽裡面填内容,并且豐富登入後的顯示

先在config/index.js,配置跨域通路路由:

proxyTable: {
    '/goods/*': {
        target: 'http://hotemotion.fun:3389',
        changeOrigin: true
      },
    '/users/*':{
      target: 'http://hotemotion.fun:3389',
      changeOrigin: true
    }           

邏輯:點選登入後應該post一個使用者的資訊(賬号、密碼),檢查使用者的登入狀态。并且get一個carList的資料

登入事件:showSignout() 傳遞使用者名和密碼給後端,判斷正确後顯示登陸後的資訊

退出事件:_getLogout()  将資訊清空

(使用者名和密碼都用了v-model 綁定輸入的資料)

src/components/m-header.vue: 

<template>
<div>
  <div class="header">
    <div class="logo">
      <img src="/static/images/logo.jpg">
    </div>
    <div class="sign">
        <p class="signin" v-if="showLoginOut" @click = "showLogin()">登入</p>
        <div class="signout" v-if="!showLoginOut">
          <span class="sign-name" v-text="userName"></span>
          <span class="sign-out" @click="_getLogout">退出</span>
          <router-link to="/car" class="sign-car">購物車</router-link>
        </div>
    </div>
  </div>
  <my-dialog :is-show="showLogDialog" @on-close="closeDialog('showLogDialog')">
    <!-- my-dialog 插件控制彈窗,父元件綁定is-show屬性傳遞給子元件,并且根據值判斷彈窗是否展示 -->
    <div class="signin-slot">
      <p class="signin-logo">登入:</p>
      <form>
        <div class="signin-name">
          <span class="name-icon icon">1</span>
          <input type="input" name="username" placeholder="使用者名" v-model="userName"/>
        </div>
        <div class="signin-psd">
          <span class="pwd-icon icon">2</span>
          <input type="password" name="password" placeholder="密碼" v-model="userPwd">
        </div>
        <button type="button" class="signin-submit" @click="showSignout">登入</button>
      </form>
    </div>
  </my-dialog>
</div>
</template>

<script>
import axios from 'axios'
import Dialog from './base/dialog'

export default {
  data() {
    return {
      showLogDialog: false,
      showLoginOut : true,
      userName:'',
      userPwd:'',
    }
  },
  // 重新整理後能夠保持登入狀态
  mounted() {
    this._getCheckLogin();
  },
  methods: {
    closeDialog(attr) {
      this[attr] = false
    },
    // 顯示登入視窗
    showLogin() {
      this.showLogDialog = true
    },
    //檢查登入狀态
    _getCheckLogin() {
      axios.get('/users/checkLogin').then((res) => {
        if (res.data.status == '0') {
          this.showLoginOut = false
          this.userName = res.data.result.userName
          this.getCartList()
        }
      })
    },
    // 登出
    _getLogout() {
      axios.post('/users/logout').then((res) => {
        if (res.data.status == '0') {
          this.showLoginOut = true
          this.userName = ''
          this.userPwd = ''
        }
      })
    },
    // 登入
    showSignout() {
      axios.post('/users/login',{
        userName: this.userName,
        userPwd: this.userPwd,
      }).then((res) => {
        if (res.data.status == '0') {
          // console.log(res)
          this.showLogDialog = false;
          this.showLoginOut = false;
        }
      })
    }
  },
  components: {
    MyDialog: Dialog
  }
}
</script>
<style type="text/css" scoped>

</style>
           

此時重新啟動npm run dev,就能夠在控制台看到登入後取得的資料。此時加上頁面樣式,該頁面基本資訊完成。

11. 購物車頁面

學習一個flex的布局技巧: width:1%;

子元件count.vue的運用,以及父元件的傳參

route(路線), router(路由) 傻傻分不清楚。

    this,$route.query.addressId (得到路徑上的參數)

    this.$router.push()       ( 跳轉到某一路由)

12.   使用Vuex管理資料

安裝:

npm install vuex --save           

利用Vuex得到商品的數量,用于在購物車中顯示。

src/store/store.js: 

state 用來存儲變量的狀态

mutations:記錄變量狀态的變化(setCartCount是設定cartCount初始值,updateCartCount 改變cartCount數值)

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    cartCount:0
  },
  mutations: {
    setCartCount(state,cartCount){
      state.cartCount = cartCount;
    },
    updateCartCount(state,cartCount){
      state.cartCount += cartCount;
    }
  }
});
export default store
           

src/ components/goods.vue:

_addToCar() 添加到購物車就加一個數。

import store from './../store/store'

export default {
    methods: {
    _addToCar(productId) {
      //post 送出資料
      addToCar(productId).then((res) => {
        //mmp, 這個狀态碼是字元串
        if (res.data.status == '0') {
          this.showAddCart = true
          // 如果請求成功,資料存入store中
          store.commit('updateCartCount', 1)
        } else {
          this.showErrDialog = true
        }
      })
    },
  }
}           

src/components/car.vue: 

點選按鈕改變數量的時候狀态加1或減1, 删除的時候則删除目前的數量

import store from '../store/store'

export default {
  methods: { 
   editNum(flag, item) {
      if (flag === 'min') {
        if (item.productNum === 1) {
          return
        }
        item.productNum--
        store.commit('updateCartCount', -1)
      } else {
        item.productNum++
        store.commit('updateCartCount', 1)
      }
    },
    delItem() {
      axios.post('/users/carDel', {
        productId: this.productId
      }).then((res) => {
        if (res.data.status == '0') {
          this.showDelDialog = false
          this.getCarList()
          store.commit('updateCartCount', -this.productNum)
        }
      })
    }
  }           

在m-header.vue中使用:

<template>
  <router-link to="/car" class="sign-car">購物車{{carCount}}</router-link>
</template>
<script>
import store from '../store/store'

export default {
  // 重新整理的時候也檢查登入狀态
  mounted() {
    this._getCheckLogin();
  },
  computed: {
    carCount() {
      return store.state.cartCount
    }
  },
  methods: {
    // 登出
    _getLogout() {
          store.commit('setCartCount', 0)
    },
    // 獲得商品資料,存入store中
    getCartList() {
      axios.get('/users/carList').then((res) => {
        if (res.data.status == '0') {
          let cartCount = 0
          const carList = res.data.result
          carList.forEach((item) => {
            cartCount += item.productNum
            // console.log(cartCount)
            store.commit('setCartCount', cartCount)
          })
        }
      })
    }
}

</script>