1. 程式人生 > >小米商城 -- vue專案實戰

小米商城 -- vue專案實戰

僅以該文記錄專案過程。

賬號: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.  下拉載入

下載元件:

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>

相關推薦

小米商城 -- vue專案實戰

僅以該文記錄專案過程。 賬號:sunyu    密碼:123456        該專案是對小米商城系統的模仿,實現了從瀏覽商品到結算商品的整個過程,其中包括了商品列表、根據價格篩選商品、對商品 排序、登入、加入購物車、結算等功能 前臺使用vue-cli構建了請求伺

Apicoud+vue開發高效能商城APP專案實戰教程

第一章:專案概述 001:apicloud平臺介紹。 目前所流行的webapp開發平臺的引入,webapp開發的趨勢和能做的事情。 002:知識體系架構介紹。 vue.js的引入介紹,apicloud模組機制的優勢和選型,開發工具phpstorm和webstorm的推薦使用。 第二章:apicloud快速入

從零開始Vue專案實戰(三)-專案結構

現在在瀏覽器中輸入http://localhost:8083,可以看到初始的“Welcome to Your Vue.js App”頁面了 目錄結構 ├── README.md 專案介紹 ├── index.html 入口頁面 ├── build

vue 專案實戰 (生命週期鉤子)

開篇先來一張圖 下圖是官方展示的生命週期圖 Vue例項的生命週期鉤子函式(8個)         1. beforeCreate          

從零開始Vue專案實戰(二)-搭建環境

1、下載node.js並安裝 下載地址:https://nodejs.org/en/download/。 下載.msi 格式的直接連續下一步就可以了。安裝完成後可以用 node -v 和 npm -v 檢視版本號。 2、安裝vue-cli 腳手架構建工具 在命令列中輸入npm ins

從零開始Vue專案實戰(一)-準備篇

從前參與過一個react專案的程式碼編寫,大神搭建的框架,我主要負責業務邏輯程式碼編寫,現在回想起來似乎又什麼都不會,現在為了鞏固前端知識,決定用Vue來做這個專案的移動端網站,我本人Vue是從零開始的,一邊學習一邊寫程式碼,在這裡記錄一下過程。 專案說明: 主要功能實現一個投資平臺,會員身份為融資人或投

vue專案實戰

本文實戰為主,沒有基礎,真正的基礎是要從實戰開始::: 安集vue整合環境: npm install -g vue-cli   執行vue檢查安裝情況: Options: -V, --version output the version number -h, --help output u

(生命週期鉤子)vue 專案實戰

(生命週期鉤子)vue 專案實戰 開篇先來一張圖 下圖是官方展示的生命週期圖   Vue例項的生命週期鉤子函式(8個) 1. beforeCreate   剛 new了一個元件,無法訪問到資料和真實的dom,基本上這個好像不能幹啥 2. created    d

Vue專案實戰優化:已有元件優化系列(一)

一_原有元件效果 其中,核取方塊為一個元件,根據資料庫中的值,進行是否勾選,並且核取方塊只能是禁用的 二_原有元件程式碼 <template> <input v-if="gearboxtype === 'A'" checked type="

vue專案實戰(二)之首頁layout佈局

一、替換顯示頁面 1.在 src/components目錄下新建Layout.vue檔案: <template> <div> <h2>header</h2> <h2>con

Vue專案實戰引入百度地圖(二)

一、在 http://lbsyun.baidu.com/ 申請 祕鑰 二、在index.html檔案中引入 <script type="text/javascript" src="https://api.map.baidu.com/api?v=3.0&ak=Fh9X4h

Vue專案實戰引入百度地圖(一)

一、在 http://lbsyun.baidu.com/ 申請 祕鑰 二、在index.html檔案中引入 <script type="text/javascript" src="https://api.map.baidu.com/api?v=3.0&ak=Fh9X4h

vue專案實戰(一)之vue-cli腳手架搭建專案

首先假如你已經安裝了node和npm,如果沒有的話自己百度安裝一下。 如果感覺npm下載速度慢,可以使用淘寶映象cnpm,連結地址: http://npm.taobao.org/ 安裝cnpm 方式一: npm install -g cnpm --registry

vue專案實戰總結筆記

公司專案也快接近尾聲,在做專案的過程中,自己也遇到好多坑,個人覺得語法結構規範嚴謹對頁面呈現的效果尤為重要。 確認專案框架 一般頁面都分為公共的頭部和底部,還有中間渲染的內容。 主要開始工作:封

Vue專案實戰(二)- 引入JQuery等第三方庫

友情連結 1、說明 引入JQuery庫的方式有多種,我曾經試過用npm直接把jquery安裝配置入專案,但是在後續開發中,尤其是用到基於jquery的第三方外掛的時候,遇到了很多的問題,所以這裡還是介紹一種非常簡單非常容易上手且沒有後顧之憂的方式。

淺談Vue專案實戰(頁面渲染+事件繫結)

前言:專案使用vue,記錄搭建專案到上線心得,會一直跟新……… 頁面渲染 vue是不會去操作dom節點,是有資料去操控節點,在js檔案資料都在data裡 *js程式碼片* export def

vue專案實戰中的增、刪、改、查

現在公司專案是做的後臺管理系統,那麼無疑要用到增、刪、改、查。其實實戰裡的增刪改查都要呼叫介面,傳遞引數,而很多的dom操作都反而不需要了。 vue有個很關鍵的詞對增刪改查很重要,叫做雙向資料繫結。因為你需要不斷的傳參,傳值,接收id,原生DOM的操作能不用就不用,耗效能,

vue專案實戰經驗彙總

目錄 1.vue框架使用注意事項和經驗 1.1 解決Vue動態路由引數變化,頁面資料不更新 1.2 vue元件裡定時器銷燬問題 1.3 vue實現按需載入元件的兩種方式 1.4 元件之間,父子

基於vue-cli網上商城專案實戰開發——搭建一個完整的SPA專案開發框架(一)

基於vue-cli腳手架,結合實際專案經驗,搭建一個完整的SPA專案框架。 安裝vue-cli腳手架 先貼出官方的命令列工具使用方法 官方命令列工具 鑑於此過程比較緩慢,我這裡推薦使用淘寶映象來安裝。依次執行以下步驟 (本人mac,需要sudo獲

SSH學習02 【SSH網上商城專案實戰02】基本增刪查改、Service和Action的抽取以及使用註解替換xml

【SSH網上商城專案實戰02】基本增刪查改、Service和Action的抽取以及使用註解替換xml 轉自:https://blog.csdn.net/eson_15/article/details/51297698 上一節我們搭建好了Struts2、Hibernate和Spring的開