一、分頁排序案例 後端負責提供介面(3000) 前端負責業務邏輯(8080) 介面地址:從8080跨域到3000拿數據 http://127.0.0.1:3000/shouji http://127.0.0.1:8080/api/shouji 後端app.js var express = requi ...
一、分頁排序案例
後端負責提供介面(3000)
前端負責業務邏輯(8080)
介面地址:從8080跨域到3000拿數據
http://127.0.0.1:8080/api/shouji
分頁排序介面: http://127.0.0.1:3000/shouji?page=1&pagesize=5&sortby=price&sortdirection=dao
代理跨域回來的數據介面地址: http://127.0.0.1:8080/api/shouji?page=1&pagesize=5&sortby=price&sortdirection=dao
後端app.js
var express = require("express"); var url = require("url"); var app = express(); var arr = [ {"id" : 1 , "title" : "蘋果A" , "price" : 1699}, {"id" : 2 , "title" : "蘋果B" , "price" : 1999}, ... {"id" : 14 , "title" : "蘋果N" , "price" : 8888} ]; app.get("/shouji" , function(req,res){ var obj = url.parse(req.url, true).query; var page = obj.page; //頁碼 var pagesize = obj.pagesize; //每頁顯示的數量 var sortby = obj.sortby; //排序條件 var sortdirection = obj.sortdirection; //排序條件(正序或倒序) //按照id或價格排序 arr = arr.sort(function(a,b){ if(sortdirection == "zheng"){ return a[sortby] - b[sortby]; }else if(sortdirection == "dao"){ return b[sortby] - a[sortby]; } }) //提供數據給前端 res.json({ "number" : arr.length , //商品總數量 "results": arr.slice((page - 1) * pagesize, page * pagesize) //顯示多少條數據 }) }); app.listen(3000);示例代碼
前端main.js
import Vue from "vue"; import Vuex from "vuex"; import App from "./App.vue"; import store from "./store"; Vue.use(Vuex); new Vue({ el : "#app", store, render : (h) => h(App) })示例代碼
新建taobao文件夾存放三要素,然後在文件夾的index.js中引入三要素:
state.js、action.js、mutations.js三個文件:
export default { ... }
store/index.js
import Vue from "vue"; import Vuex from "vuex"; import createLogger from "vuex/dist/logger"; import counterState from "./counter/state.js" import counterMutations from "./counter/mutations.js" import counterActions from "./counter/actions.js" import taobaoState from "./taobao/state.js" import taobaoMutations from "./taobao/mutations.js" import taobaoActions from "./taobao/actions.js" Vue.use(Vuex); //全局數據 const store = new Vuex.Store({ state : { counterState, taobaoState }, //同步的(commit) mutations : { ...counterMutations, ...taobaoMutations }, //非同步的(dispatch) actions : { ...counterActions, ...taobaoActions }, plugins : [createLogger()] }); export default store;示例代碼
state.js存儲預設數據:
export default { page : 1, pagesize: 5, sortby : "id", sortdirection:"zheng", number : 0, results :[] }示例代碼
App.vue
<template> <div> <table> <tr> <th>編號</th> <th>商品</th> <th>價格</th> </tr> </table> </div> </template> <script> export default { created(){ //生命周期,當組件被創建時觸發,發出一個非同步請求介面數據 this.$store.dispatch("init"); } } </script>示例代碼
actions.js
export default { async init({commit,state}){ var page = state.taobaoState.page; var pagesize = state.taobaoState.pagesize; var sortby = state.taobaoState.sortby; var sortdirection = state.taobaoState.sortdirection; //發出非同步的get請求拿數據 var {results,number} = await fetch(`/api/shouji?page=${page}&pagesize=${pagesize} &sortby=${sortby}&sortdirection=${sortdirection}`).then(data => data.json()); //數據從後端拿回來後,改變results和number //改變state只能通過mutations commit("changeResults", {results}) commit("changeNumber", {number}) } }示例代碼
mutations.js,此時可以從控制台logger中查看請求數據成功,然後回到App.vue的結構顯示數據。
export default { changeResults(state , payload){ state.taobaoState.results = payload.results; }, changeNumber(state, payload) { state.taobaoState.number = payload.number; } }示例代碼
回到App.vue顯示數據和換頁:
<template> <div> <table> <tr v-for="item in $store.state.taobaoState.results"> <td>{{item.id}}</td> <td>{{item.title}}</td> <td>{{item.price}}</td> </tr> </table> <button v-for="i in allPage()" @click="changePage(i)">{{i}}</button> </div> </template> <script> export default { created(){ //生命周期,當組件被創建的時候觸發 this.$store.dispatch("init"); }, computed:{ allPage(){ //計算總頁碼數:總數量 / 每頁數量,向上取整 var _state = this.$store.state.taobaoState; return Math.ceil(_state.number / _state.pagesize) } }, methods : { //分頁頁碼跳轉 changePage(page){ this.$store.dispatch("changePage", {page}); } } } </script>示例代碼
actions.js
export default { async init({commit,state}){ ... }, //其他都和init一樣,只改名字即可 async changePage({commit,state},{page}){ //改變page commit("changePage", {page}) //湊齊4個數據 var page = state.taobaoState.page; var pagesize = state.taobaoState.pagesize; var sortby = state.taobaoState.sortby; var sortdirection = state.taobaoState.sortdirection; //發出請求和init方法的一樣 var {results, number} = await fetch(`/api/shouji?page=${page}&pagesize=${pagesize} &sortby=${sortby}&sortdirection=${sortdirection}`).then(data => data.json()); //改變state只能通過mutations commit("changeResults", {results}) commit("changeNumber", {number}) } }示例代碼
mutations.js
export default { changeResult(state , payload){ state.taobaoState.results = payload.results; }, changeNumber(state, payload) { state.taobaoState.number = payload.number; }, //頁碼跳轉 changePage(state , payload){ state.taobaoState.page = payload.page; } }示例代碼
App.vue下麵實現每頁顯示多少條:
<template> <div> <table> <tr v-for="item in $store.state.taobaoState.results"> <td>{{item.id}}</td> <td>{{item.title}}</td> <td>{{item.price}}</td> </tr> </table> <button v-for="i in allPage()" @click="changePage(i)">{{i}}</button> <select v-model="pagesize"> <option value="3">每頁3條</option> <option value="5">每頁5條</option> <option value="10">每頁10條</option> </select> </div> </template> <script> export default { data(){ return { pagesize : this.$store.state.taobaoState.pagesize } }, created(){ //生命周期,當組件被創建的時候觸發 this.$store.dispatch("init"); }, methods : { changePage(page){ this.$store.dispatch("changePage" , {page}); } }, //v-mode的值不能加圓括弧,所以不能直接計算,先通過data(){}中計算,再用watch監聽變化 //Vue提供一種更通用的方式來觀察和響應Vue實例上的數據變動:偵聽屬性。 //以V-model綁定數據時使用的數據變化監測 //使用watch允許我們執行非同步操作 watch : { pagesize(v){ //當pagesize改變,發出一個請求,去改變pagesize this.$store.dispatch("changePageSize" , {pagesize : v}); } } } </script>示例代碼
actions.js
export default { async init({commit,state}){ ... }, async changePageSize({commit,state},{pagesize}){ //改變page commit("changePageSize", {pagesize:pagesize}) //湊齊4個數據 var page = state.taobaoState.page; var pagesize = state.taobaoState.pagesize; var sortby = state.taobaoState.sortby; var sortdirection = state.taobaoState.sortdirection; //發出請求 var {results,number} = await fetch(`/api/shouji?page=${page}&pagesize=${pagesize} &sortby=${sortby}&sortdirection=${sortdirection}`).then(data => data.json()); //改變state只能通過mutations commit("changeResults", {results}) commit("changeNumber", {number}) } }示例代碼
mutations.js
export default { //...省略 changePage(state , payload){ state.taobaoState.page = payload.page; }, changePageSize(state, payload) { state.taobaoState.pagesize = payload.pagesize; } }示例代碼
下麵實現id和價格的排序
App.vue
<template> <div> <table> <tr> <th> id: <button @click="changeSort('id','dao')">↓</button> <button @click="changeSort('id','zheng')">↑</button> </th> <th>商品:</th> <th> 價格: <button @click="changeSort('price','dao')">↓</button> <button @click="changeSort('price','zheng')">↑</button> </th> </tr> <tr v-for="item in $store.state.taobaoState.results"> <td>{{item.id}}</td> <td>{{item.title}}</td> <td>{{item.price}}</td> </tr> </table> <button v-for="i in allPage()" @click="changePage(i)" :class="{'cur':$store.state.taobaoState.page == i}"> {{i}} </button> </div> </template> <script> export default { methods : { changePage(page){ this.$store.dispatch("changePage", {page}); }, changeSort(sortby , sortdirection){ this.$store.dispatch("changeSort", {sortby , sortdirection}); } } } </script> <style> .cur{ background : orange;} </style>示例代碼
actions.js封裝成函數:
async function load(commit, state){ //湊齊4個 var page = state.taobaoState.page; var pagesize = state.taobaoState.pagesize; var sortby = state.taobaoState.sortby; var sortdirection = state.taobaoState.sortdirection; //發出請求 var {results,number} = await fetch(`/api/shouji?page=${page}&pagesize=${pagesize}&sortby=${sortby}&sortdirection=${sortdirection}`).then(data => data.json()); //數據從後端拿回來後,改變results和number //改變state只能通過mutations commit("changeResults", { results}) commit("changeNumber", { number }) } export default { async init({commit , state}){ await load(commit , state); }, async changePage({ commit, state } , {page}) { //改變page commit("changePage", { page: page}) await load(commit, state); }, async changePageSize({ commit, state }, { pagesize }) { //改變pagesize commit("changePageSize", { pagesize: pagesize }) //頁碼歸1 commit("changePage", { page: 1 }) await load(commit, state); }, //排序 async changeSort({commit, state}, {sortby, sortdirection}){ //改變pagesize commit("changeSort", { sortby, sortdirection}) //頁碼歸1 commit("changePage", { page: 1 }) await load(commit, state); }, }示例代碼
mutations.js
export default { //...省略 changePageSize(state, payload) { state.taobaoState.pagesize = payload.pagesize; }, changeSort(state , payload){ state.taobaoState.sortby = payload.sortby; state.taobaoState.sortdirection = payload.sortdirection; } }示例代碼
二、Vue-cli
2.1 Vue-cli的安裝
Vue 提供一個官方命令行工具(CLI),可用於快速搭建大型單頁應用。該工具為現代化的前端開發工作流提供了開箱即用的構建配置。只需幾分鐘即可創建並啟動一個帶熱重載、保存時靜態檢查以及可用於生產環境的構建配置的項目。
Vue-cli是Vue的快速起步工具(腳手架工具),再也不用手動配webpack。
Vue-loader的官網:
https://cn.vuejs.org/v2/guide/installation.html
https://vue-loader.vuejs.org/zh-cn/start/setup.html
在全局安裝vue-cli:
npm install -g vue-cli
創建一個基於webpack模板的新項目文件夾,並初始化配置:
vue init webpack hello-vue
vue init webpack-simple hello-vue
vue init webpack-simple項目預設打包後只有一個html和js文件(適合小項目)
vue init webpack項目預設打包完之後,會有很標準的目錄(適合中大型項目)
兩種方式初始化Vue-cli項目的目錄差別很大,你會發現vue init webpack的方式初始化項目,預設提供了很多webpack的配置,也更加方便你對代理(跨域)、最終打包資源放到伺服器什麼目錄、以及js、css、img和項目在打包過程等優化的配置等。
vue init webpack |
vue init webpack-simple |
|
|
安裝依賴:
npm install
啟動項目:
npm run dev
2.2 Vue-cli的配置講解
"scripts": { "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot", "build": "cross-env NODE_ENV=production webpack --progress --hide-modules" },
cross-env NODE_ENV=development 將環境變數設置成開發模式
cross-env NODE_ENV=production 將環境變數設置成生產模式
--open 自動開啟瀏覽器
--hot 開啟熱更新, 熱更新就是保存後進行局部刷新
打開項目以後 vue-cli給我們配置了很多東西。
.editorconfig對編輯器的統一配置,是讓大家的代碼有一個規範、代碼縮進形式的統一,當大家提交代碼後使用不同的編輯器打開時,顯示的代碼格式是一樣的
root = true [*] charset = utf-8 indent_style = space //空格縮進 indent_size = 4 //統一縮進為4個 end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true
關於生產模式的配置
開發過程不需要優化配置,只有在生產模式下,才需要優化、css壓縮打包到一個文件,js合併壓縮,關於性能優化,小圖片會轉成base64 減少http請求。
if (process.env.NODE_ENV === 'production') { module.exports.devtool = '#source-map' // http://vue-loader.vuejs.org/en/workflow/production.html module.exports.plugins = (module.exports.plugins || []).concat([ new webpack.DefinePlugin({ 'process.env': { NODE_ENV: '"production"' } }), new webpack.optimize.UglifyJsPlugin({ sourceMap: true, compress: { warnings: false } }), new webpack.LoaderOptionsPlugin({ minimize: true }) ]) }
將vue-cli提供的src文件夾中的assets圖片文件夾,移動到根目錄外面去,就是為了不讓圖片webpack編譯打包。
vue中使用圖片的兩種方式:
第一種:傳統方式
<img src="../assets/logo.png">
第二種:使用vue的v-bind指令來使用data數據中的圖片:
<img :src="imgSrc"> <script> export default { data () { return { imgSrc : "../assets/logo.png" } } } </script>
webpack將png的圖片變成base64,使用url-loader
{ test: /\.(png|jpg|gif|svg)$/, loader: 'url-loader', options: { limit: 8192 } }
limit是設置一個圖片大小的臨界點,值小於8192位元組的圖片就轉成base64圖片源碼,好處就是能減少一個HTTP請求。
2.3項目打包上線
如果把自己的項目放到伺服器運行,就需要使用npm run build將自己的項目打包出來。
然後在dist文件夾下麵,就有打包、優化好的項目文件、打包好的項目文件可以放到伺服器中運行。
註意:項目啟動一定要在伺服器環境下運行,在webpack伺服器、node、phpnow伺服器都可以。
三、酷表單項目
main.js
import Vue from "vue"; import Vuex from "vuex"; import App from "./App.vue"; Vue.use(Vuex); // 創建一個全局倉庫 const store = new Vuex.Store({ state : { } }) new Vue({ el : "#app", store, render : (h) => h(App) })示例代碼
第一步:寫靜態頁面組件,App.vue
<template> <div> <div class="warp"> <div