1. 程式人生 > >Web前端學習筆記——VueJS-APP案例

Web前端學習筆記——VueJS-APP案例

在這裡插入圖片描述 原始碼下載

將專案原始碼託管到oschina中

  1. 點選頭像 -> 修改資料 -> SSH公鑰 如何生成SSH公鑰

  2. 建立自己的空倉儲,使用 git config --global user.name "使用者名稱"git config --global user.email ***@**.com 來全域性配置提交時使用者的名稱和郵箱

  3. 使用 git init 在本地初始化專案

  4. 使用 touch README.mdtouch .gitignore 來建立專案的說明檔案和忽略檔案;

  5. 使用 git add . 將所有檔案託管到 git 中

  6. 使用 git commit -m "init project"

    將專案進行本地提交

  7. 使用 git remote add origin 倉儲地址將本地專案和遠端倉儲連線,並使用origin最為遠端倉儲的別名

  8. 使用 git push -u origin master 將原生代碼push到倉儲中

  • .gitignore
node_modules
.idea
.vscode
.git
  • LICENSE
The MIT License (MIT)

Copyright (c) 2014 connors and other contributors

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

App.vue 元件的基本設定

  • index.html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</
head
>
<body style="background-color:white;"> <!-- 這是容器 --> <div id="app"></div> </body> </html>
  • webpack.config.js
// 由於 webpack 是基於Node進行構建的,所有,webpack的配置檔案中,任何合法的Node程式碼都是支援的
var path = require('path')
// 在記憶體中,根據指定的模板頁面,生成一份記憶體中的首頁,同時自動把打包好的bundle注入到頁面底部
// 如果要配置外掛,需要在匯出的物件中,掛載一個 plugins 節點
var htmlWebpackPlugin = require('html-webpack-plugin')

// 當以命令列形式執行 webpack 或 webpack-dev-server 的時候,工具會發現,我們並沒有提供 要打包 的檔案的 入口 和 出口檔案,此時,他會檢查專案根目錄中的配置檔案,並讀取這個檔案,就拿到了匯出的這個 配置物件,然後根據這個物件,進行打包構建
module.exports = {
  //mode: 'development',//Webpack4.0.0以上使用,還需安裝webpack-cli
  entry: path.join(__dirname, './src/main.js'), // 入口檔案
  output: { // 指定輸出選項
    path: path.join(__dirname, './dist'), // 輸出路徑
    filename: 'bundle.js' // 指定輸出檔案的名稱
  },
  plugins: [ // 所有webpack  外掛的配置節點
    new htmlWebpackPlugin({
      template: path.join(__dirname, './src/index.html'), // 指定模板檔案路徑
      filename: 'index.html' // 設定生成的記憶體頁面的名稱
    })
  ],
  module: { // 配置所有第三方loader 模組的
    rules: [ // 第三方模組的匹配規則
      { test: /\.css$/, use: ['style-loader', 'css-loader'] }, // 處理 CSS 檔案的 loader
      { test: /\.less$/, use: ['style-loader', 'css-loader?modules', 'less-loader'] }, // 處理 less 檔案的 loader
      { test: /\.scss$/, use: ['style-loader', 'css-loader?modules', 'sass-loader'] }, // 處理 scss 檔案的 loader
      { test: /\.(jpg|png|gif|bmp|jpeg)$/, use: 'url-loader' }, // 處理 圖片路徑的 loader
      // limit 給定的值,是圖片的大小,單位是 byte, 如果我們引用的 圖片,大於或等於給定的 limit值,則不會被轉為base64格式的字串, 如果 圖片小於給定的 limit 值,則會被轉為 base64的字串
      { test: /\.(ttf|eot|svg|woff|woff2)$/, use: 'url-loader' }, // 處理 字型檔案的 loader 
      { test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ }, // 配置 Babel 來轉換高階的ES語法
      { test: /\.vue$/, use: 'vue-loader' } // 處理 .vue 檔案的 loader
    ]
  },
  resolve: {
	extensions: ['.js', '.jsx', '.json', '.vue'],
    alias: { // 修改 Vue 被匯入時候的包的路徑
      // "vue$": "vue/dist/vue.js"
	  '@': path.join(__dirname,'./src')
    }
  }
}
  • package.json
{
  "name": "01.webpack-study",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack-dev-server --open --port 3000 --hot --host 127.0.0.1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-plugin-component": "^0.10.1",
    "babel-plugin-transform-remove-strict-mode": "^0.0.2",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-preset-env": "^1.6.1",
    "babel-preset-stage-0": "^6.24.1",
    "css-loader": "^0.28.7",
    "file-loader": "^1.1.5",
    "html-webpack-plugin": "^2.30.1",
    "less": "^2.7.3",
    "less-loader": "^4.0.5",
    "node-sass": "^4.5.3",
    "sass-loader": "^6.0.6",
    "style-loader": "^0.19.0",
    "url-loader": "^0.6.2",
    "vue-loader": "^13.3.0",
    "vue-template-compiler": "^2.5.2",
    "webpack": "^3.8.1",
    "webpack-dev-server": "^2.9.3"
  },
  "dependencies": {
    "bootstrap": "^3.3.7",
    "mint-ui": "^2.2.9",
    "moment": "^2.19.1",
    "vue": "^2.5.2",
    "vue-preview": "^1.0.5",
    "vue-resource": "^1.3.4",
    "vue-router": "^3.0.1",
    "vuex": "^3.0.1"
  }
}

  • main.js
// 入口檔案
import Vue from 'vue'
// 1.1 匯入路由的包
import VueRouter from 'vue-router'
// 1.2 安裝路由
Vue.use(VueRouter)

// 註冊 vuex
import Vuex from 'vuex'
Vue.use(Vuex)

// 每次剛進入 網站,肯定會 呼叫 main.js 在剛呼叫的時候,先從本地儲存中,把 購物車的資料讀出來,放到 store 中
var car = JSON.parse(localStorage.getItem('car') || '[]')

var store = new Vuex.Store({
  state: { // this.$store.state.***
    car: car // 將 購物車中的商品的資料,用一個數組儲存起來,在 car 陣列中,儲存一些商品的物件, 咱們可以暫時將這個商品物件,設計成這個樣子   
    // { id:商品的id, count: 要購買的數量, price: 商品的單價,selected: false  }
  },
  mutations: { // this.$store.commit('方法的名稱', '按需傳遞唯一的引數')
    addToCar(state, goodsinfo) {
      // 點選加入購物車,把商品資訊,儲存到 store 中的 car 上
      // 分析:
      // 1. 如果購物車中,之前就已經有這個對應的商品了,那麼,只需要更新數量
      // 2. 如果沒有,則直接把 商品資料,push 到 car 中即可

      // 假設 在購物車中,沒有找到對應的商品
      var flag = false

      state.car.some(item => {
        if (item.id == goodsinfo.id) {
          item.count += parseInt(goodsinfo.count)
          flag = true
          return true
        }
      })

      // 如果最終,迴圈完畢,得到的 flag 還是 false,則把商品資料直接 push 到 購物車中
      if (!flag) {
        state.car.push(goodsinfo)
      }

      // 當 更新 car 之後,把 car 陣列,儲存到 本地的 localStorage 中
      localStorage.setItem('car', JSON.stringify(state.car))
    },
    updateGoodsInfo(state, goodsinfo) {
      // 修改購物車中商品的數量值
      // 分析: 
      state.car.some(item => {
        if (item.id == goodsinfo.id) {
          item.count = parseInt(goodsinfo.count)
          return true
        }
      })
      // 當修改完商品的數量,把最新的購物車資料,儲存到 本地儲存中
      localStorage.setItem('car', JSON.stringify(state.car))
    },
    removeFormCar(state, id) {
      // 根據Id,從store 中的購物車中刪除對應的那條商品資料
      state.car.some((item, i) => {
        if (item.id == id) {
          state.car.splice(i, 1)
          return true;
        }
      })
      // 將刪除完畢後的,最新的購物車資料,同步到 本地儲存中
      localStorage.setItem('car', JSON.stringify(state.car))
    },
    updateGoodsSelected(state, info) {
      state.car.some(item => {
        if (item.id == info.id) {
          item.selected = info.selected
        }
      })
      // 把最新的 所有購物車商品的狀態儲存到 store 中去
      localStorage.setItem('car', JSON.stringify(state.car))
    }
  },
  getters: { // this.$store.getters.***
    // 相當於 計算屬性,也相當於 filters
    getAllCount(state) {
      var c = 0;
      state.car.forEach(item => {
        c += item.count
      })
      return c
    },
    getGoodsCount(state) {
      var o = {}
      state.car.forEach(item => {
        o[item.id] = item.count
      })
      return o
    },
    getGoodsSelected(state) {
      var o = {}
      state.car.forEach(item => {
        o[item.id] = item.selected
      })
      return o
    },
    getGoodsCountAndAmount(state) {
      var o = {
        count: 0, // 勾選的數量
        amount: 0 // 勾選的總價
      }
      state.car.forEach(item => {
        if (item.selected) {
          o.count += item.count
          o.amount += item.price * item.count
        }
      })
      return o
    }
  }
})

// 匯入格式化時間的外掛
import moment from 'moment'
// 定義全域性的過濾器
Vue.filter('dateFormat', function (dataStr, pattern = "YYYY-MM-DD HH:mm:ss") {
  return moment(dataStr).format(pattern)
})

// 2.1 匯入 vue-resource
import VueResource from 'vue-resource'
// 2.2 安裝 vue-resource
Vue.use(VueResource)
// 設定請求的根路徑
Vue.http.options.root = 'http://vue.studyit.io';
// 全域性設定 post 時候表單資料格式組織形式   application/x-www-form-urlencoded
Vue.http.options.emulateJSON = true;


// 匯入 MUI 的樣式
import './lib/mui/css/mui.min.css'
// 匯入擴充套件圖示樣式
import './lib/mui/css/icons-extra.css'


// 按需匯入 Mint-UI 中的元件   
/* import { Header, Swipe, SwipeItem, Button, Lazyload } from 'mint-ui'
Vue.component(Header.name, Header)
Vue.component(Swipe.name, Swipe)
Vue.component(SwipeItem.name, SwipeItem)
Vue.component(Button.name, Button)
Vue.use(Lazyload); */
import MintUI from 'mint-ui'
Vue.use(MintUI)
import 'mint-ui/lib/style.css'


// 安裝 圖片預覽外掛
import VuePreview from 'vue-preview'
Vue.use(VuePreview)


// 1.3 匯入自己的 router.js 路由模組
import router from './router.js'


// 匯入 App 根元件
import app from './App.vue'

var vm = new Vue({
  el: '#app',
  render: c => c(app),
  router, // 1.4 掛載路由物件到 VM 例項上
  store // 掛載 store 狀態管理物件
})
  1. 頭部的固定導航欄使用 Mint-UIHeader 元件;

  2. 底部的頁籤使用 muitabbar;

  3. 購物車的圖示,使用 icons-extra 中的 mui-icon-extra mui-icon-extra-cart,同時,應該把其依賴的字型圖示檔案 mui-icons-extra.ttf,複製到 fonts 目錄下!

  4. 將底部的頁籤,改造成 router-link 來實現單頁面的切換;

  5. Tab Bar 路由啟用時候設定高亮的兩種方式:

  • 全域性設定樣式如下:

	.router-link-active{

     	color:#007aff !important;

   }

  • 或者在 new VueRouter 的時候,通過 linkActiveClass 來指定高亮的類:

	// 建立路由物件

   var router = new VueRouter({

     routes: [

       { path: '/', redirect: '/home' }

     ],

     linkActiveClass: 'mui-active'

   });

  • App.vue
<template>
  <div class="app-container">

    <!-- 頂部 Header 區域 -->
    <mt-header fixed title="黑馬程式設計師·Vue專案">
      <span slot="left" @click="goBack" v-show="flag">
        <mt-button icon="back">返回</mt-button>
      </span>
    </mt-header>


    <!-- 中間的 路由 router-view 區域 -->
		<transition>
			<router-view></router-view>
		</transition>


    <!-- 底部 Tabbar 區域 -->
    <nav class="mui-bar mui-bar-tab">
			<router-link class="mui-tab-item-llb" to="/home">
				<span class="mui-icon mui-icon-home"></span>
				<span class="mui-tab-label">首頁</span>
			</router-link>
			<router-link class="mui-tab-item-llb" to="/member">
				<span class="mui-icon mui-icon-contact"></span>
				<span class="mui-tab-label">會員</span>
			</router-link>
			<router-link class="mui-tab-item-llb" to="/shopcar">
				<span class="mui-icon mui-icon-extra mui-icon-extra-cart">
					<span class="mui-badge" id="badge">{{ $store.getters.getAllCount }}</span>
				</span>
				<span class="mui-tab-label">購物車</span>
			</router-link>
			<router-link class="mui-tab-item-llb" to="/search">
				<span class="mui-icon mui-icon-search"></span>
				<span class="mui-tab-label">搜尋</span>
			</router-link>
		</nav>

  </div>
</template>

<script>
export default {
  data() {
    return {
      flag: false
    };
  },
  created() {
    this.flag = this.$route.path === "/home" ? false : true;
  },
  methods: {
    goBack() {
      // 點選後退
      this.$router.go(-1);
    }
  },
  watch: {
    "$route.path": function(newVal) {
      if (newVal === "/home") {
        this.flag = false;
      } else {
        this.flag = true;
      }
    }
  }
};
</script>


<style lang="scss" scoped>
.mint-header {
  z-index: 99;
}
.app-container {
  padding-top: 40px;
  padding-bottom: 50px;
  overflow-x: hidden;
}

.v-enter {
  opacity: 0;
  transform: translateX(100%);
}

.v-leave-to {
  opacity: 0;
  transform: translateX(-100%);
  position: absolute;
}

.v-enter-active,
.v-leave-active {
  transition: all 0.5s ease;
}

// 該類名,解決 tabbar 點選無法切換的問題
.mui-bar-tab .mui-tab-item-llb.mui-active {
  color: #007aff;
}

.mui-bar-tab .mui-tab-item-llb {
  display: table-cell;
  overflow: hidden;
  width: 1%;
  height: 50<