前端筆記之Vue(五)TodoList實戰&拆分store&跨域&練習代理跨域

1、TodoList

1.1安裝依賴

安裝相關依賴:javascript

npm install --save-dev webpack
npm install --save-dev babel-loader babel-core babel-preset-es2015
npm install --save-dev vue-loader
npm install --save-dev css-loader
npm install --save-dev vue-template-compiler
npm install --save-dev stylus stylus-loader
npm install --save vue
npm install --save vuex

 

1.2配置虛擬服務器

【第一步:安裝依賴】php

npm install -g json-server

【第二步:json-server的服務器啓動】css

啓動須要json文件做爲支撐,新建data.json文件作服務數據:html

{
    "mapList" : [
        {"id":1 ,"title" : "吃飯", "done" : false},
        {"id":2 ,"title" : "睡覺", "done" : false},
        {"id":3 ,"title" : "作飯", "done" : false},
        {"id":4 ,"title" : "掃地", "done" : false}
    ]
}

 

啓動命令json-server命令:
json-server 數據文件路徑 -s 靜態化目錄 -p 8080

json-server www/data/data.json -s ./www -p 8080
-s是 --static
-p是 --port

 

最終沒有使用webpack-dev-server模擬服務器前端

 

配置webpack.config.js文件:vue

const path = require('path');
const {VueLoaderPlugin} = require('vue-loader');  //最新版webpack須要引入插件

module.exports = {
     //程序的入口文件
     entry: "./www/app/app.js",

     //程序的出口(打包的文件)
     output : {
        //打包文件輸出的路徑
        path : path.resolve(__dirname, "www/dist"),
        //打包文件的名稱
        filename : "all.js",
        // publicPath:"/public" //這是對webpack-dev-server的配置,配置虛擬路徑
     },
     //讓webpack監聽變化,自動打包
     watch : true,
     mode : "development",
     //配置webpack的模塊插件
     module:{
        //關於模塊的配置規則
        rules : [
            {
                //模塊規則(配置 loader、解析器等選項)
                test : /\.js$/,  //解析的時候匹配到的都是js文件
                include: [
                  path.resolve(__dirname, "www/app")    //翻譯什麼文件夾
                ],
                exclude: [
                  path.resolve(__dirname, "node_modules") //不翻譯什麼文件夾
                ],
                loader : "babel-loader",
                options : { presets : ["es2015"] }
            },
            {
                test: /\.vue$/,
                include: [
                  path.resolve(__dirname, "www/app")    //翻譯什麼文件夾
                ],
                exclude: [
                  path.resolve(__dirname, "node_modules") //不翻譯什麼文件夾
                ],
                loader: 'vue-loader',
                options :{ loaders : { stylus:'vue-style-loader!css-loader!stylus-loader' } }
            },
            {
                test:/\.css$/,
                use: ['vue-style-loader','css-loader']
            }
            // {
            //     test: /\.styl(us)?$/,
            //     use: [
            //         'vue-style-loader',
            //         'css-loader',
            //         'stylus-loader'
            //     ]
            // }
        ]
     },
     resolve: {
        alias: { //配置別名
          'vue$': 'vue/dist/vue.esm.js' // 用 webpack 1 時需用 'vue/dist/vue.common.js'
        }
     },
     //最新版webpack須要引入插件
     plugins : [
        new VueLoaderPlugin()
     ]
}

 

【第三步:訪問接口】java

獲取全部的數據:GETnode

增長數據:POSTjquery

獲得某一條數據:GETwebpack

刪除某一條:DELETE

更新原始數據:PUT (更新條目的全部的屬性)、PATH(更新條目的某一個屬性)

自帶分頁:page(第幾頁)limit(每頁有多少條)

http://localhost:8080/mapList          返回.json文件全部數據(數組)
http://localhost:8080/mapList/1        返回id=1的數據,採用這種路徑風格id必須爲小寫(數組)
http://localhost:8080/mapList/?Name=lst  返回Name=lst的用戶數據(數組)

分頁查詢:參數爲 _start, _end, _limit,並可添加其它參數篩選條件,如:
http://localhost:8080/mapList?_start=6&_limit=3
http://localhost:8080/mapList?_start=3&_end=6

排序:參數爲_sort, _order 
http://localhost:8080/mapList?_sort=id&_order=asc
http://localhost:8080/mapList?_sort=user,views&_order=desc,asc 

操做符:_gte, _lte, _ne, _like
_gte大於,_lte小於, _ne非, _like模糊查詢,q關鍵詞查詢
http://127.0.0.1:8080/mapList/?q=吃

1.3 TodoList

查詢數據

相關步驟:

created生命週期中發出一個GETALL的異步命令,去actions裏面發異步請求。

 

App.vue

<script>
    export default {
        created(){ this.$store.dispatch("GETALL"); }
    }
</script>

 

main.js

import Vue from "vue";
import Vuex from "vuex";
import App from "./App.vue";
Vue.use(Vuex);

const store = new Vuex.Store({
   state : { todos : [] }, mutations: { GETALL(state,payload){ // state.todos.push(payload)
            state.todos = payload; } },
    actions :{ async GETALL({commit}){ //請求數據庫中的數據,而後存儲到state的todos中
            var data = await fetch("/maplist").then(data=>data.json());
            //發出commit()命令,而且將參數當載荷傳遞過去
            commit("GETALL", data);
        }
    }
});

new Vue({
    el : "#app",
    store,
    render:(h)=>h(App)
})

異步請的數據回調成功後,將數據以載荷的形式發送到mutations,再去修改state 的數據

state全局倉庫有了數據,就能夠在App.vue進行循環渲染。

 

App.vue

<template>
    <div>
        <ul>
            <li v-for="item in todos">
                {{item.title}}
            </li>
        </ul>
    </div>
</template>
<script>
    export default {
        created(){
            this.$store.dispatch("GETALL");
        },
        computed : {
            todos(){ return this.$store.state.todos }
        }
    }
</script>

 

下一步:須要將li標籤拆分紅組件:

App.vue

<template>
    <div>
        <ul>
           <li is="TodoLi" v-for="item in todos" :item="item"></li>
        </ul>
    </div>
</template>
<script> import TodoLi from "./components/TodoLi.vue";
    export default {
        created(){
            this.$store.dispatch("GETALL");
        },
        computed : {
            todos(){
                return this.$store.state.todos
            }
        },
        components:{
            TodoLi
        }
    }
</script>

 

TodoLi.vue

<template>
     <li>{{item.title}}</li>
</template>
<script>
    export default {
        props : ["item"]
    }
</script>

刪除數據

接下來寫增刪改查業務,推薦先寫刪除,由於刪除值須要id

TodoLi.vue

<template>
     <li>
         <span>{{item.title}}</span>
         <button @click="del(item.id)">刪除</button>
    </li>
</template>
<script>
    export default {
        props : ["item"],
        methods:{
            del(id){ this.$store.dispatch("DEL", {id}) }
        }
    }
</script>
 
const store = new Vuex.Store({
    state : {
        todos : []
    },
    mutations: {
        GETALL(state,payload){
            // state.todos.push(payload)
            state.todos = payload;
        },
        DEL(state, payload){ // 根據id刪除state的數據
            state.todos = state.todos.filter(item=>{
                return item.id != payload.id; }) }
    },
    actions :{
        async GETALL({commit}){
            //請求數據庫中的數據,而後存儲到state的todos中
            var data = await fetch("/maplist").then(data=>data.json());
            //發出commit()命令,而且將參數當載荷傳遞過去
            commit("GETALL", data);
        },
        async DEL({commit},payload){ //向服務器發出刪除請求,刪除data.json中的數據
            var data = await fetch("/maplist/" + payload.id, {
                method:"DELETE",
            }).then(data => data.json());
            commit("DEL", payload); //刪除全局state倉庫的數據
 },
    }
});

 

新增業務

App.vue

<template>
    <div>
        <div>
            <input type="text" v-model.trim="txt">
            <button @click="add">新增</button>
        </div>
        <ul>
           <li is="TodoLi" v-for="item in todos" :item="item"></li>
        </ul>
    </div>
</template>
<script>
    import TodoLi from "./components/TodoLi.vue";
    export default {
        data(){
            return {
               txt : ''
            }
        },
        methods :{
            add(){ if(this.txt == '') return; //發出新增的異步請求
                this.$store.dispatch(ADD, {id: new Date() - 0, title:this.txt, done:false}) this.txt = "" }
        },
        components:{
            TodoLi
        }
    }
</script>

 

main.js

actions : {
    //新增數據
    async ADD({ commit }, payload) {
        //向data.json文件中插入數據
        var data = await fetch("/maplist/", {
            method: "POST",
            headers:{'Content-type' : 'application/json'},
            body: JSON.stringify(payload)
        }).then(data => data.json());
        commit("ADD", data); //新增數據到state,影響視圖更新
    }
},
mutations : {
    ADD(state, payload) { state.todos.push(payload); }
}

 

修改數據

TodoLi.vue

<template>
     <li>
         <span v-if="!isShow" @dblclick="showInput">{{item.title}}</span>
         <input type="text" v-if="isShow" v-model="item.title" @blur="hideInput(item)" v-focus>
         <button @click="del(item.id)">刪除</button>
    </li>
</template>
<script>
    export default {
        props : ["item"],
        data(){
            return{
                isShow:false
            }
        },
        methods:{
            del(id){
                this.$store.dispatch("DEL", {id})
            },
           showInput(){ //雙擊顯示input
                this.isShow = !this.isShow; }, hideInput(item){ console.log(item) //失去焦點隱藏input,而且發送CAHNGETITLE命令修改title內容
                this.isShow = !this.isShow; this.$store.dispatch("CHANGETITLE",item) }
        },
        directives:{ //自定義組件指令,自動獲取焦點
 focus :{ inserted(el){ el.focus(); } } }
    }
</script>

 

main.js

const store = new Vuex.Store({
    state : {
        todos : []
    },
    mutations: {
        CHANGETITLE(state, payload) {
            // 寫法1
            // state.todos.forEach(item=>{
            //     if (item.id == payload.id){
            //         item.title = payload.title;
            //     }
            // })
            // 寫法2
            state.todos = state.todos.map(item => {
                if(item.id == payload.id) {
                    return payload
                }
                return item; })
        }
    },
    actions :{
        //修改請求
        async CHANGETITLE({commit}, payload) {
            var data = await fetch("/maplist/" + payload.id, {
                method: "PATCH",
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(payload)
            }).then(data => data.json());

            commit("CHANGETITLE", data); //雖然實現了修改,可是爲了完整性仍是寫上
 },
    }
});

 

修改任務事件:當前任務是否作了,須要一個複選框

todoli.vue

<li>
    <input type="checkbox" v-model="item.done" ref="cbox" @click="changeDone(item)">
<spanv-if="!isShowInput"@dblclick="showInput" :class="{cur:item.done}">{{item.title}}</span>
</li>
<script>
methods:{
changeDone(item){
       console.log(this.$refs.cbox.checked);
       // 這裏使用的是ref鉤子 這樣能獲得 複選框的狀態 
       // 提交的時候 只須要提交 id  複選框的狀態就好了
       this.$store.dispatch("CHANGEDONE",{
          id : item.id,
          done : this.$refs.cbox.checked
       })
}
}
</script>
<style>
    .cur{text-decoration: line-through;}
</style>

 

app.js修改done和修改title的方式方法都同樣,只要改方法名便可。

const store = new Vuex.Store({
    mutations:{
        CHANGEDONE(state, payload){
            state.todos = state.todos.map(item => {
                if(item.id == payload.id){
                    return payload
                }
                return item
            })
        }
   },
actions:{
        async CHANGEDONE({commit},payload){
            var data = await fetch("/mapList/" + payload.id,{
                "method" : 'PATCH',
                "headers":{
                    'Content-Type':"application/json"
                },
                body:JSON.stringify({done:payload.done})
            }).then(res => res.json()); 
            commit("CHANGEDONE",data)
        },
    }
});

篩選按鈕:計算已作未作事項

篩選按鈕:計算已作未作事項

app.js

const store = new Vuex.Store({
    state:{
        todos:[]
    },
    mutations:{
        ...
    },
    actions:{
        ...
    },
    getters:{ yizuo:function(state){
            return state.todos.filter(item => {
                return item.done == true //true表示已作
            })
        },
        weizuo:function(state){
            return state.todos.filter(item => {
                return item.done == false //false表示未作
 }) } }
});

 

App.vue

<template>
    <div>
        <div>
            <input type="text" v-model.trim="txt">
            <button @click="add">新增</button>
        </div>
        <ul>
            <li v-for="item of todos" is="TodoLi" :item="item"></li>
        </ul>
        <div>
                所有:{{$store.state.todos.length}}個事項<br>
                已作:{{$store.getters.yizuo.length}}個完成事項<br>
                未作:{{$store.getters.weizuo.length}}個代辦事項<br>
        </div>
        <div>
            <button @click="all">查看所有</button>
            <button @click="yizuo">查看已作</button>
            <button @click="weizuo">查看未作</button>
        </div>
    </div>
</template>
<script>
import todoli from './components/TodoLi.vue'
export default {
    data() {
        return {
            txt: '',
            state: 'all'
        }
    },
    computed: {
        todos() { if(this.state == 'all'){ return this.$store.state.todos }else if(this.state == 'yizuo'){ return this.$store.getters.yizuo }else if(this.state == 'weizuo'){ return this.$store.getters.weizuo } }
    },
    methods: {
       all() { this.state = 'all' }, yizuo() { this.state = 'yizuo' }, weizuo() { this.state = 'weizuo' }
    }
}
</script>

全部業務都已經完成,可是因爲組件和數據太亂,下面開始拆分store


 

2、拆分store

咱們都知道vuexvue用來集中管理狀態的容器(管理全局的狀態),實現不一樣組件之間相互的數據訪問。咱們說一下vuex拆分store以及多模塊管理。若是一個項目很是大的話狀態就會很是的多,若是不進行分類處理,全部的狀態都維護在一個state裏面的話,狀態管理就會變得很是的混亂,這樣很是不利於項目的後期維護。如今前端推崇模塊化開發,爲的就是提升開發效率和維護效率,避免重複工做。那麼vuex是怎麼樣解決這個問題的呢?這個時候咱們今天要講的主角modules就要閃亮登場了。 

 

第一步:將main.js中的store拆分到一個js文件中。

export const storeObj = {
    state:{
        ...
    },
    mutations:{
        ...
    },
    actions:{
       ...
    },
    getters:{
        ...
    }
}

 

store中的index.jsmain.js中引入

import {storeObj} from "./store/index.js";
const store = new Vuex.Store(storeObj);

 

第二步:拆分statemutationsactionsgetters

給他們分別建立單獨的js文件,默認暴露

export default {

}

 

能夠將咱們定義的這些對象加入到Vuexstore

storeindex.jsimport引入:

import state from "./state.js";
import mutations from "./mutations.js";
import actions from "./actions.js";
import getters from "./getters.js";

export const storeObj = {
    state:{
        ...state
    },
    mutations:{
        ...mutations
    },
    actions:{
        ...actions
    },
    getters:{
        ...getters
    }
}
示例代碼

 

因爲沒裝翻譯...」對象解構語法,會報錯:

npm install --svae-dev babel-plugin-transform-object-rest-spread

 

配置webpack.config.js

{
    test: /\.js?$/,  //解析的時候匹配到的都是js
    loader: "babel-loader",
    //翻譯字典
    options: {
        presets: ["es2015","ES2015"],
        plugins: ["transform-object-rest-spread"]
    }
},

配置完成後就能夠識別...」解構了。

至此,還沒拆完,使用常量代替mutations集合actionstype名字

 

新建一個types.js文件,在裏面存常量(大寫字母的方法)

注意:把這些常量放到單獨的文件中可讓你的代碼合做者對整個app包含mutationactions一目瞭然。

用不用常量代替取決於你--在須要多人協做的大型項目中,這會頗有幫助,可是若是你不喜歡,徹底能夠不這麼作。

export const GETALL = "GETALL";
export const DEL = "DEL";
export const ADD = "ADD";
export const CHANGETITLE = "CHANGETITLE";
export const CHANGEDONE = "CHANGEDONE";

 

暴露常量的名字後,分別在mutationsactionsjs文件中使用這些來代替:

mutations.js

import {GETALL,DEL,ADD,CHANGETITLE,CHANGEDONE} from "./types.js";
export default {
    [GETALL](state, payload) {
        
    },
    [DEL](state, payload) {
        
    },
    [ADD](state, payload) {
        
    },
    [CHANGETITLE](state, payload) {
        
    },
    [CHANGEDONE](state, payload) {
        
    }
}

 

actions.js

import {GETALL,DEL,ADD,CHANGETITLE,CHANGEDONE} from "./types.js";
export default {
    async [GETALL]({ commit }) {
        
    },
    async [DEL]({ commit }, payload) {
        
    },
    async [ADD]({ commit }, payload) {
        
    },
    async [CHANGETITLE]({ commit }, payload) {
        
    },
    async [CHANGEDONE]({ commit }, payload) {
        
    }
}

注意:上方mutationsactions中的[types.ADD]寫法,由於types.ADD是一個對象,因此不能直接當作函數名來寫,須要用到ES2015風格的計算屬性命名功能來使用一個常量做爲函數名,才能使用。

https://vuex.vuejs.org/zh/guide/mutations.html


3、異步請求數據(跨域)

3.1 Ajax不能跨域

好比在Apache中演示:

<html>
<head>
    <title>Document</title>
</head>
<body>
    <script src="jquery-3.3.1.min.js"></script>
    <script> $.get("http://127.0.0.88/a.txt" , function(data){ console.log(data); }); </script>
</body>
</html>

試圖在127.0.0.1請求127.0.0.88/a.txtJSON數據,會報錯:

 

瀏覽器會阻止對ip地址不一樣,或者端口號不一樣的數據請求。

此時咱們必需要進行請求,就是跨域技術。


3.2jQuery複習JSONP跨域

<html>
<head>
    <title>Document</title>
</head>
<body>
    <script>
        function haha(info){ console.log(info); } </script>
    <script src="http://127.0.0.88/a.txt"></script>
</body>
</html>

在頁面上定義一個函數,而後用script標籤引入這個語句,執行這個語句。此時數據就經過函數的實參和形參的結合,傳入了頁面。script沒有跨域限制的,能夠輕鬆src引入其餘ip地址的js文件。

JSONP叫作JSON Padding(補白)

咱們寫一個接口,這個接口不是一個JSON,而是一個語句,這個語句是函數的調用

 

升級:把a.txt改成a.php(這個文件不須要會,由於是後端的事情)

<?php
$callback = $_GET["callback"];    //獲取get請求
echo $callback . '({"a" : 100 })';//JSON參數
?>

 

 

點擊按鈕再發出JSONP跨域請求。

本質上是點擊按鈕的瞬間,建立了一個script標籤,script標籤的src指向了咱們剛剛寫的那個接口,那個接口是函數的調用。咱們快速定義這個函數,使得src引入的js可以調用這個函數,從而經過實參和形參的結合,將數據傳入頁面。

<script>
    $("button").click(function(){
         //建立script標籤
         var $o = $("<script><\/script>");
         //建立一個src
         $o.attr("src" , "http://127.0.0.88/a.php?callback=xixi");
         //定義全局函數
         window.xixi= function(data){
             //接收到數據的回調函數
             console.log(data);
         }
         //上樹
         $("head").append($o); 
         //下樹
 $o.remove();
     });
</script>

 

但實際上不用這麼麻煩,jQuery會自動幫咱們發出jsonp跨域:

<html lang="en">
<head>
    <title>Document</title>
</head>
<body>
    <button>按我發出請求</button>
    <script> $("button").click(function(){ $.ajax({ "dataType" : "JSONP" , "url" : "http://127.0.0.88/a.php", "success" : function(data){ console.log(data); } }) }); </script>
</body>
</html>

jQuery會隨機生成一個函數名。

 

原理和咱們寫的同樣的,都是:

1)瞬間建立一個內部函數

2)瞬間建立一個script標籤,src指向咱們的url地址

3)瞬間上樹

4)瞬間下樹


3.3跨域方法1JSONP跨域

以前咱們項目的數據和前端的文件都是同源的(就是在同一個接口下)。

可是,工做中,必定是要跨域請求數據的。

好比咱們的前端項目運行在8080端口,要請求3000端口的數據,就是跨域。

事實上,工做中,模擬接口必定是不一樣ip的,模擬接口運行在辦公室的局域網上的。

每一個人的電腦都是同一個局域網的,後臺哥哥會給你一個後端接口文檔,接口在演示的時候,頗有多是30008000等等。但你的前端項目跑在webpack-dev-server8080端口,就涉及到跨域請求數據了。

 

建立一個後端文件夾(server_side)和前端項目文件夾(Vue_study):

 

前端後端共同跑:後端3000,前端8080

 

 

app.js

var express = require("express");
var app = express();

app.get("/a", function(req,res){
    // res.json({"a":100});
    res.jsonp({"a":100}); //jsonp()能自動獲得callback參數請求
})

app.listen(3000);
示例代碼

http://127.0.0.1:3000/a?callback=haha

 

 

App.vue

<template>
    <div>
        <h1>首頁</h1>
        <button @click="addServer">請求數據</button>
    </div>
</template>
<script>
export default {
    methods:{
        addServer(){
            $.ajax({
                dataType:"JSONP",
                url: "http://127.0.0.1:3000/a",
                success:function(data){
                    console.log(data)
                }
            })
        }
    }
};
</script>
示例代碼

 

3.4跨域方法2CORS跨域

面試想要回答的好,看下面文章:

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

http://www.ruanyifeng.com/blog/2016/04/cors.html

跨域資源共享(CORSCross-Origin Resource Sharing)機制容許Web應用服務器進行跨域訪問控制,從而使得跨域數據傳輸得以安全進行。瀏覽器支持在API容器中(例如XMLHttpRequestfetch)使用CORS,以下降跨域HTTP請求所帶來的風險。

 

說白了,就是在HTTP下響應的頭部加一句話。

CORS是一個W3C標準,全稱是"跨域資源共享"Cross-origin resource sharing)。

它容許瀏覽器向跨源服務器,發出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制

 

咱們在後端通常就加Access-Control-Allow-Origin 值爲*

 

問題:8080的前端頁面請求3000後端的頁面,是誰禁止的?是瀏覽器禁止的,爲了安全。此時就要寫一個HTTP下行響應頭部,來告訴瀏覽器,此次請求是容許的,這是最簡單的跨域方法,可是IE8纔開始兼容。

 

 

app.js後端:

var express = require("express");
var app = express();

app.get("/a", function(req,res){
    //表示容許任何域名來源的請求
    res.setHeader("Access-Control-Allow-Origin", "*");
    res.json({a:100});
})

app.listen(3000);

 

App.vue此時在前端項目中就能夠隨意跨域:

<template>
    <div>
        <h1>首頁</h1>
        <button @click="addServer">請求數據</button>
    </div>
</template>
<script>
export default {
    methods:{
        addServer(){
           $.get("http://127.0.0.1:3000/a", function(data){
                console.log(data)
           })
        }
    }
}
</script>
示例代碼

3.5跨域請求方法3:代理跨越(proxy

「代理」就是偷數據。

PHP作例子,實現一下偷百度首頁(瞭解便可)

<?php
    echo file_get_contents("http://www.baidu.com/");
?>

運行tou.php就直接是百度首頁了。

 

 

好比京東充話費接口,能夠被後端偷來:

 

 

而後在前端項目中使用:

<body>
    <h1>手機歸屬地查詢(業績最快,徹底免費)</h1>
    <input type="text" id="tel">
    <button>查詢</button>
</body>
<script type="text/javascript" src="js/jquery-2.2.4.min.js"></script>
<script type="text/javascript">
    $("button").click(function(){
        var tel = $("#tel").val();
        //能夠請求本身服務器的數據,只不過數據由後端tou.php偷回來。
        $.get("http://127.0.0.1:8088/tou.php?tel=" + tel, function(data){
            console.log(data)
        })
    });
</script>
示例代碼


【重點】:如何在VueReact項目中使用代理跨域?

webpack-dev-server能夠幫咱們偷服務端的數據,美其名曰「代理」。

至關於服務器去「偷數據」,由後端(前端的後端,就是webpack-dev-server)出面,問3000端口要數據

 

webpack.config.js中,加幾句話便可實現「代理跨域」。

https://webpack.docschina.org/configuration/dev-server/#devserver-proxy

webpack-dev-server這個小型服務器底層也是express實現的

 

webpack-dev-server在幫咱們作幾件事:

1)構建app文件夾到/public/all.js

2)靜態化www文件夾提供了靜態文件的路由

3)代理了127.0.0.1:3000的接口。

4)構建app的時候進行了翻譯

 

webpack.config.js配置:

var path = require('path');
const {VueLoaderPlugin} =  require("vue-loader"); //最新版webpack須要引入此插件

module.exports = {
    //程序的入口文件
    entry: './www/app/app.js',
    //程序的出口文件(被打包的文件)
    output: {
      ...
    },
    //自動監聽
    watch:true,
    mode : "development",
    //配置webpack的模塊插件
    module:{
        // 關於模塊配置
        ...
    },
    resolve: {
        ...
    },
   devServer: { proxy: { '/api': {
                target: 'http://127.0.0.1:3000', //設置你調用的接口域名和端口
                //這裏理解成/api代理target中的地址,後面組件中調用接口要使用/api代替
                pathRewrite: {'^/api' : ''}
            }
        }
    },
    //最新版webpack須要引入此插件
    plugins:[
       new VueLoaderPlugin()
    ]
};

這些配置都從webpack官網抄的,配置就能夠作項目了,實現接口的請求。

配置好後,重啓 npm run dev好比3000有一個接口/a,如今將被代理到8080接口的/api/a

http://127.0.0.1:3000/a這個接口,被「代理」到http://127.0.0.1:8080/api/a 

 

 

 

 

 

若是後端app.js出一個這樣的接口:http://127.0.0.1/:3000/a

app.get("/a",function(req,res){
    res.json({"a":100});
 });

 

前端app.js就能夠這樣獲取後端的接口:http://127.0.0.1/:8080/api/a

<template>
    <div>
        <h1>首頁</h1>
        <button @click="addServer">請求數據</button>
    </div>
</template>
<script>
export default {
    methods : {
        addServer(){
            $.get("http://127.0.0.1:8080/api/a",function(data){ console.log(data); })
        }
    }
}
</script>

總結:一提起「跨域」,立馬回答他一共有三種方法。


4、練習代理跨域

後端app.js提供數據接口:(node app.js運行)

var express = require("express");
var app = express();
app.get("/a" , function(req,res){
    res.json({"a":100});
});
app.listen(3000);
示例代碼

 

前端main.js

import Vue from "vue";
import Vuex from "vuex";
import App from "./App.vue";
import store from "./store";

new Vue({
    el:"#app",
    store,
    render:(h)=>h(App)
})

 

前端App.vue:

<template>
    <div>
        <h1>{{$store.state.counterState.a}}</h1>
        <button @click="add(1)">加1</button>
        <button @click="add(2)">加2</button>
      <button @click="addServer">按我加服務器的數據</button>
    </div>
</template>
<script>
    export default {
        methods : {
            add(n){ this.$store.commit("ADD", {n});
          },
            addServer(){ //異步必須用dispatch
                this.$store.dispatch("ADDSERVER");
            }
        }
    }
</script>

 

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";

Vue.use(Vuex);
//全局數據
export default new Vuex.Store({
    state: { counterState }, //同步的(commit)
    mutations: {
        ...counterMutations
    },
    //異步的(dispatch)
 actions : { ...counterActions },
    plugins: [createLogger()]
});

 

state.js

export default {
    a: 100
}
實例代碼

 

mutations.js

export default {
    ADD(state, payload) {
        state.counterState.a += payload.n;
    } 
}

 

actions.js

export default {
    async ADDSERVER({commit}){ //發出異步請求
        const {a} = await fetch("/api/a").then(data=>data.json());
        //異步函數不能改變state,改變state只有mutations
        commit("ADD" , {n:a}) //觸發mutation
  }
}
相關文章
相關標籤/搜索