官網下載node:https://nodejs.org/zh-cn/download/javascript
node -V #node版本 npm -V #npm版本
npm install vue npm install --global vue-cli
vue init webpack vue-study #初始化 cd vue-study #進入項目文件夾
項目建立好css
npm run dev
項目運行成功html
"lint-fix": "eslint --fix --ext .js --ext .jsx --ext .vue src/",
格式錯誤能夠經過vue
npm run lint-fix
安裝vuexjava
npm i vuex -D
新建store文件夾及其如下文件node
import Vue from 'vue' import vuex from 'vuex' import mutations from './mutations/mutations' import actions from './actions/actions' import getters from './getters/getters' import state from './state/state' Vue.use(vuex) export default new vuex.Store({ state, getters, actions, mutations })
store/store.jsjquery
import store from './store/store' new Vue({ el: '#app', router, store, components: { App }, template: '<App/>' })
引入storewebpack
A.state和gettersios
state/state.jsweb
getters.js
mutations.js,actions.js都是export default{}形式
export default { name: 'App', mounted: function () { this.useStore() }, methods: { useStore () { console.log(this.$store.state.count) // -> 0 } }, computed: { fullName () { return this.$store.getters.fullName } } }
App.vue
npm run dev
運行
打印出store裏的state,獲得getters裏面的值
B.mutations,actions
export default { updateCountAsync (store, data) { setTimeout(() => { store.commit('updateCount', { num: data.num }) }, data.time) } }
actions.js
export default { updateCount (state, {num, num2}) { state.count = num } }
mutations
dispatch用來觸發actions,和commit用來觸發mutations同樣
{{this.$store.state.count}} mounted: function () { this.useStore() this.useMutations() // 執行後當即變成20 this.$store.dispatch('updateCountAsync', { num: 5, time: 2000 }) // 執行後2秒變成5 }, methods: { useStore () { console.log(this.$store.state.count) // -> 0 }, useMutations () { this.$store.commit('updateCount', { num: 20, num2: 2 }) } },
App.vue
npm run dev
2秒以後從20變成5
C.讓store使用更便捷
<script> import { mapState, mapGetters } from 'vuex' export default { name: 'App', mounted: function () { }, methods: { }, computed: { ...mapState(['count']), ...mapGetters(['fullName']) } }
使用map語法更簡潔得到state和getters裏的值。
A.axios和proxyTable解決get跨域問題
npm i axios -D #安裝axios
import axios from 'axios' Vue.prototype.$axios = axios
src/main.js全局添加axios
拿到一個本地數據
jsonview後的視圖
proxyTable: { '/api': { target: 'http://localhost:8000', changeOrigin: true, pathRewrite: { '^/api': '/' } } },
config/index.js
API_HOST: '/api/'
condfig/dev.env.js增長API_HOST
API_HOST: '"http:/xxx.xxx.xxx.xxx:8000"' // 生產環境的地址,上線後修改
config/prod.env.js增長線上地址接口
mounted: function () { this.getapi() }, methods: { getapi () { this.$axios.get('/api/article/', { params: {format: 'json'} }) .then((res) => { console.log(res) }) .catch(function (error) { console.log(error) }) } }
App.vue內調用,注意接口格式
npm run dev
啓動開發環境
查看控制檯輸出跨域接口信息
B.qs解決post發送兼容問題
import qs from 'qs' Vue.prototype.$axios = axios Vue.prototype.$qs = qs
main.js
postapi () { let data = this.$qs.stringify({'schools': 1, 'id': 1}) /* 接口請求 */ this.$axios.post('/api/userSchoolFav/', data) .then((res) => { console.log('POST數據Fav返回值:', res) }) .catch(function (error) { console.log(error) }) }
或者qs非全局註冊
import Qs from 'qs' export default { methods:{ postapi () { let data = Qs.stringify({'schools': 1, 'id': 1}) /* 接口請求 */ this.$axios.post('/api/userSchoolFav/', data) .then((res) => { console.log('POST數據Fav返回值:', res) }) .catch(function (error) { console.log(error) }) } }
當前頁面引入並使用
C.解決跨域攜帶token信息(JWT的方式不是cookie,因此這裏暫時用不上)
axios.defaults.withCredentials = true // 容許跨域攜帶cookie信息
以jwt的token爲例:
參考:https://my.oschina.net/u/3018050/blog/2054854
安裝jquery
npm install jquery -D
const webpack = require('webpack')
plugins: [ new webpack.ProvidePlugin({ $: "jquery", jQuery: "jquery", jquery: "jquery", "window.jQuery": "jquery" }) ],
添加build/webpack.base.conf.js相關plugin
import 'jquery'
main.js
jquery: true// 添加
能夠得到到,jquery可使用
安裝styl-loader
npm install stylus stylus-loader -D
<style scoped lang="stylus">
語言上lang='stylus'便可
<style lang="stylus"> @import "assets/base.styl"
外部引用
以element UI爲例
安裝element ui
npm i element-ui -S #安裝element-ui npm i sass-loader node-sass -D #安裝sass-loader,node-sass
/* 改變主題色變量 */ $--color-primary: teal; /* 改變 icon 字體路徑變量,必需 */ $--font-path: '../../node_modules/element-ui/lib/theme-chalk/fonts'; @import "../../node_modules/element-ui/packages/theme-chalk/src/index";
新建src/assets/element-variables.scss文件
import Element from 'element-ui' import './assets/element-variables.scss' Vue.use(Element)
使用element ui
主要按鈕的主題色定義好
在main.js裏添加每一個跳轉前的路由鉤子。這裏是經過JWTtoken是否存在,以及跳轉頁面是否爲登陸頁、註冊頁、或者我的中心(例如我的信息頁面)等,肯定對localstorage裏存儲的token是否進行刪除,以及是否須要跳轉回登陸頁面
對request攔截,判斷localstorage裏的token是否存在,來添加authorization認證信息,確保登陸成功的狀態下,每次發送信息攜帶JWTtoken,使得一些須要用戶權限的頁面可以順利經過
對response攔截,判斷返回信息中是否有用戶未登陸401,或者登陸認證錯誤403的狀況,若是有,則返回登陸頁面
這裏對路由鉤子和http攔截判斷打印數字,以便在控制檯更好看到操做時,走的邏輯路徑
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' import router from './router' import store from './store/store' import axios from 'axios' import qs from 'qs' // import 'jquery' import Element from 'element-ui' import './assets/element-variables.scss' import IndexHeader from '@/layout/Header' import IndexFooter from '@/layout/Footer' import Banner from '@/components/Banner' import Pages from '@/components/Pages' Vue.use(Element) Vue.component('IndexHeader', IndexHeader) Vue.component('IndexFooter', IndexFooter) Vue.component('Banner', Banner) Vue.component('Pages', Pages) router.beforeEach(({name}, from, next) => { // 獲取 JWT Token if (localStorage.getItem('JWT_TOKEN')) { // JWT_TOKEN存在 console.log(1) if (name === 'login' || name === 'register') { // 登陸按鈕點擊,清楚JWT Token store.commit('DELSTORELOG') console.log(2) next() } else { // 其餘頁面返回 console.log(3) next() } } else { // JWT_TOKEN不存在 console.log(4) if (name === 'Information') { // 查看我的信息頁面 console.log(5) next({name: 'login'}) } else { console.log(6) next() } } }) // http request 攔截器 axios.interceptors.request.use( config => { if (localStorage.JWT_TOKEN) { // 判斷是否存在token,若是存在的話,則每一個http header都加上token console.log(7) config.headers.Authorization = `JWT ${localStorage.JWT_TOKEN}` console.log('存在', localStorage.JWT_TOKEN) } else { console.log('不存在') } return config }, err => { console.log(8) return Promise.reject(err) }) // http response 攔截器 axios.interceptors.response.use( response => { console.log(9) return response }, error => { console.log(10) if (error.response) { console.log(11) console.log('axios:' + error.response.status) switch (error.response.status) { case 401: // 返回 401 清除token信息並跳轉到登陸頁面 store.commit('DELSTORELOG') router.replace({ path: 'login', query: {redirect: router.currentRoute.fullPath} }) break case 403: // 返回 403 清除token信息並跳轉到登陸頁面 store.commit('DELSTORELOG') router.replace({ path: 'login', query: {redirect: router.currentRoute.fullPath} }) break } } return Promise.reject(error.response.data) // 返回接口返回的錯誤信息 }) Vue.prototype.$axios = axios Vue.prototype.$qs = qs axios.defaults.withCredentials = true // 容許跨域攜帶cookie信息(例如session等),使用localstorage設置爲false Vue.config.productionTip = false /* eslint-disable no-new */ new Vue({ el: '#app', router, store, components: { App }, template: '<App/>' })
main.js
SETUSERINFO (state, info) { state.userInfo = info }
this['SETSTORELOG'](res.data.token)
import { SETUSERINFO } from '../mutation-types.js' export default { [SETUSERINFO] (state, info) { state.userInfo = info } }
新建store/mutation-types.js
this.SETSTORELOG(res.data.token)
1)增長mutation-types.js後,須要在mutations.js裏引入,而且將全部方法名用[]括起來。
2)二者引入都徐亞用map from vuex的方式,而且在methods裏添加該方法
3)使用時,無mutation-types須要將方法名用[]括起來,而有mutation-types時,則直接使用,不須要[]
import axios from 'axios' export default { ajaxGet (api, cb) { axios.get(api).then(cb).catch(err => { console.log(err) }) }, ajaxPost (api, post, cb) { axios.post(api, post).then(cb).catch(err => { console.log(err) }) } }
新建src/axios/http.js
import http from './axios/http' Vue.prototype.$http = http
在main.js中引入
<template> <div id="app"> <IndexHeader></IndexHeader> <div @click="GetMethod">axios封裝get方法</div> <div @click="PostMethod">axios封裝post方法</div> <router-view/> <IndexFooter></IndexFooter> </div> </template> <script> export default { name: 'App', methods: { GetMethod () { this.$http.ajaxGet('/api/article/', res => { console.log('ajaxGet', res) }) }, PostMethod () { this.$http.ajaxPost('/api/userSchoolFav/', {'schools': 1}, res => { console.log('ajaxPost', res) }) } } } </script>
在.vue文件中使用
點擊後可在控制檯看到相關內容。
這種封裝方式更簡化了寫法,不須要then,catch這些關鍵字,專心寫裏面的處理邏輯
由此,咱們能夠將一些經常使用方法封裝起來
新建src/axios/methods.js來保存經常使用方法,方便在調用
import axios from 'axios' export default { ajaxGetArticle (api) { axios.get(api).then((res) => { console.log('ajaxGetArticle', res) }).catch(err => { console.log(err) }) }, ajaxPostUserSchoolFav (api, post) { axios.post(api, post).then((res) => { console.log('ajaxPostUserSchoolFav', res) }).catch(err => { console.log(err) }) } }
<template> <div id="app"> <IndexHeader></IndexHeader> <div @click="GetMethod">axios封裝get方法method</div> <div @click="PostMethod">axios封裝post方法method</div> <router-view/> <IndexFooter></IndexFooter> </div> </template> <script> import http from './axios/methods.js' export default { name: 'App', methods: { GetMethod () { http.ajaxGetArticle('/api/article/') }, PostMethod () { http.ajaxPostUserSchoolFav('/api/userSchoolFav/', {'schools': 2}) } } } </script>
.vue裏引用方法並使用
能夠看到頁面可以調用。
目的和使用:
這種方式在rest模式下,當數據格式和返回status一致時,提供很好的使用方法。
好比,咱們要調用不少列表數據時,寫了不少不一樣的.vue下模板,填充數據,就能夠用一條流水線的方式來處理。
把axios發送get請求,對得到列表統一置入當前this的data下,這樣的方式封裝好。
而後統一在method裏使用這個方法帶上url參數便可。
固然,填寫表單也是這個思路,只是多個post傳遞數據對象,表單還要對返回的錯誤提示進行提醒,也就是error裏操做顯示給用戶看。前面咱們都是把method方法和error打印進行統一處理,如今能夠針對不一樣的error代碼獨立出來再也不封裝便可靈活使用
舉例:
import axios from 'axios' export default { ajaxgetList (api, that) { axios.get(api).then((res) => { console.log(res.data.results) if (res.status === 200) { that.list = res.data.results that.allCount = res.data.count } else { that.$message.error('獲取失敗') } }).catch(err => { console.log('cuole', err) }) } }
axios/methods.js,寫入方法,傳入that指代this
schoolList局部引入
schoolList一行代碼調用
同理,teacherList局部引入
同理,teacherList一行代碼調用
如此便可方便使用。
import axios from 'axios' export function ajaxgetList2 (api, that) { axios.get(api).then((res) => { console.log(res.data.results) if (res.status === 200) { that.list = res.data.results that.allCount = res.data.count } else { that.$message.error('獲取失敗') } }).catch(err => { console.log(err) }) }
若是隻是一個方法單獨在一個文件裏,能夠導出爲命名方法
兩種引用方法均可
使用不須要http下了
import * as types from './mutation-types'; // 提交mutation function makeAction (type) { return ({ commit }, ...args) => commit(type, ...args); }; export const setShopList = makeAction(types.SET_SHOPLIST);
actions.js
import * as types from './mutation-types'; import cookie from '../static/js/cookie'; import {getShopCarts} from '../api/api' // 相似於事件 每一個mutation都有字符類型的事件類型和回調函數 //全局引入vue import Vue from 'vue'; import Axios from 'axios'; Vue.prototype.$http = Axios export default { [types.SET_SHOPLIST] (state) { //設置購物車數據 // token = cookie.getCookie('token') if(cookie.getCookie('token') != null){ getShopCarts().then((response)=> { // 更新store數據 state.goods_list.goods_list = response.data; console.log(response.data) var totalPrice = 0 response.data.forEach(function(entry) { totalPrice += entry.goods.shop_price*entry.nums }); state.goods_list.totalPrice = totalPrice; }).catch(function (error) { console.log(error); }); } }, }
mutations.js
// 獲取購物車數據 export const SET_SHOPLIST = 'SET_SHOPLIST';
mutation-types.js
addShoppingCart () { //加入購物車 addShopCart({ goods: this.productId, // 商品id nums: this.buyNum, // 購買數量 }).then((response)=> { this.$refs.model.setShow(); // 更新store數據 this.$store.dispatch('setShopList'); }).catch(function (error) { console.log(error); }); },
.vue中method方法使用
import {getStore} from '../util/mUtils' import axios from 'axios' // 全局狀態控制引入 import store from '../store/store' import router from '../router' // http request 攔截器 axios.interceptors.request.use( config => { if (localStorage.JWT_TOKEN) { // 判斷是否存在token,若是存在的話,則每一個http header都加上token // 1.不設置有效期 // config.headers.Authorization = `JWT ${localStorage.JWT_TOKEN}` // 2.設置有效期 let JWT_TOKEN = getStore('JWT_TOKEN') config.headers.Authorization = `JWT ${JWT_TOKEN}` } else { } return config }, err => { return Promise.reject(err) }) // http response 攔截器 axios.interceptors.response.use( response => { return response }, error => { if (error.response) { console.log('axios:' + error.response.status) switch (error.response.status) { case 401: // 返回 401 清除token信息並跳轉到登陸頁面 store.commit('DELTOKEN') router.replace({ path: 'login', query: {redirect: router.currentRoute.fullPath} }) break case 500: console.log('服務器錯誤') // case 403: // // 返回 403 清除token信息並跳轉到登陸頁面 // store.commit('DELTOKEN') // router.replace({ // path: 'login', // query: {redirect: router.currentRoute.fullPath} // }) // break } } return Promise.reject(error.response.data) // 返回接口返回的錯誤信息 })
新建src/axios/index.js,把main.js中關於http攔截器部分所有剪切過來
在main.js中引入
對圖片src是否存在,404等狀況設置默認圖
<!-- 404Img --> <template> <div style="width:100%;height:500px;border:2px solid red"> <img :src="avatar?avatar:defaultNoImage" :onerror="defaultImg" alt="" > </div> </template> <script> export default { name: 'Demo404Img', data () { return { defaultImg: 'this.src="' + require('../assets/images/banner1.jpg') + '"', defaultNoImage: 'this.src="' + require('../assets/images/banner2.jpg') + '"', avatar: '../static/images/avatar-1.jpg' } } } </script>
1.[Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.
resolve: { alias: { 'vue$': 'vue/dist/vue.js' } }
2.npm install時,報錯:正在生成解決方案配置「Release|x64」。
npm config set sass_binary_site https://npm.taobao.org/mirrors/node-sass/
設置全局鏡像源,以後再涉及到 node-sass
的安裝時就會從淘寶鏡像下載。
3.服務器http://localhost:8080要求用戶輸入用戶名和密碼
還未解決
1.vuex官方中文文檔:https://vuex.vuejs.org/zh-cn/
2.詳解 Vue & Vuex 實踐:https://zhuanlan.zhihu.com/p/25042521
3.運用JS設置cookie、讀取cookie、刪除cookie:https://www.cnblogs.com/limeiky/p/6927305.html
4.Django框架基於session的登陸/註銷實現:https://www.cnblogs.com/cllovewxq/p/7878248.html
5.先後端分離之JWT(JSON Web Token)的使用:http://www.javashuo.com/article/p-pylxbsfz-mt.html
6.Vue 中使用 jQuery:https://blog.csdn.net/anxin_wang/article/details/78788773
7.在vue項目中使用stylus:https://blog.csdn.net/shooke/article/details/75907388
8.Vue的elementUI實現自定義主題:https://blog.csdn.net/wangcuiling_123/article/details/78513245
9.【Vue】axios請求的方法封裝和運用:https://blog.csdn.net/lgysjfs/article/details/80407130
10.node-sass 安裝失敗的解決辦法:https://lzw.me/a/node-sass-install-helper.html#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95%E4%B8%80%EF%BC%9A%E4%BD%BF%E7%94%A8%E6%B7%98%E5%AE%9D%E9%95%9C%E5%83%8F%E6%BA%90
11.vue 顯示圖片404的解決辦法:https://blog.csdn.net/qq_15576765/article/details/83823700