vue2 学习

1、vue-router 的使用

vue-router官方文档javascript

路由实现方式:css

  1. 传统开发方式 URL 改变后,马上发生请求响应整个页面,有可能资源过多致使页面出现白屏。
  2. 单页面应用 SPA (Single Page Application),锚点改变后,不会马上发送请求,而是在某个合适的时机,发起 Ajax 请求,页面局部渲染。

1. vue-router 实现原理的简单实现

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue-router</title>
</head>
<body>
    <a href="#/login">登陆</a>
    <a href="#/register">注册</a>
    <div id="app"></div>
    <script type="text/javascript" src="../node_modules/vue/dist/vue.js"></script>
    <script type="text/javascript">
        var objDiv = document.getElementById('app');

        window.onhashchange = function() {
            console.log(location.hash);
            switch(location.hash) {
                case '#/login':
                    objDiv.innerHTML = '<h2>我是登陆页面</h2>'
                    break;
                case '#/register':
                    objDiv.innerHTML = '<h2>我是注册页面</h2>'
                    break;
                default:
                    objDiv.innerHTML = '<h2>未找到页面</h2>'
                    break
            }
        }
    </script>
</body>
</html>

2. vue-router 的基本使用

VueRouter 引入以后,Vue 实例会自动挂载$router、$route 两个属性对象,组件会继承 Vue 实例上的这两个对象。
经过这两个对象,能够在组件内部得到路由相关的属性。$router就是VueRouter对象;经过$route.params能够获取动态路由参数;经过$route.query能够获取 URL 参数。html

当 Vue 不是全局对象(如使用脚手架工具进行开发)时,须要将 VueRouter 对象挂载到 Vue 对象上,而后才能使用 VueRouter。前端

vue-router的基本使用示例:vue

Vue.use(VueRouter);  // 当Vue不是全局对象时,须要将VueRouter挂载到Vue对象上

let Login = {
    template: "<div>我是登陆页面</div>"
};
let Register = {
    template: "<div>我是注册页面</div>"
};

// 建立router对象
var router = new VueRouter({
    // 配置路由对象
    routes: [
        // 路由匹配规则
        {
            path: "/login",
            component: Login
        },
        {
            path: "/register",
            component: Register
        }
    ]
});

let App = {
    template: `
        <div>
            <router-link to='/login'>登陆页面</router-link>
            <router-link to="/register">注册页面</router-link>
            <router-view></router-view>
        </div>
    `
};

new Vue({
    el: "#app",
    components: {App},
    router: router,  // 将router路由对象交给Vue实例管理
    template: "<App/>"
})
  • 引入 vue-router 模块后,会有两个全局的组件 router-link、router-view
    • router-link 组件至关于<a>标签,它的to属性至关于<a>标签的href属性;
    • router-view 组件是路由匹配组件的出口。

3. 命名路由

命名路由就是给路由规则添加name属性,而后将 router-link 组件的to属性改成v-bind属性绑定。java

Vue.use(VueRouter);

let Login = {
    template: "<div>我是登陆页面</div>"
};
let Register = {
    template: "<div>我是注册页面</div>"
};

// 建立router对象
var router = new VueRouter({
    routes: [
        {
            name: "login",  // 路由命名
            path: "/login",
            component: Login
        },
        {
            name: "register",  // 路由命名
            path: "/register",
            component: Register
        }
    ]
});

let App = {
    template: `
        <div>
            <router-link :to="{name: 'login'}">登陆页面</router-link>
            <router-link :to="{name: 'register'}">注册页面</router-link>
            <router-view></router-view>
        </div>
    `
};

new Vue({
    el: "#app",
    components: {App},
    router: router,  // 将router路由对象交给Vue实例管理
    template: "<App/>"
})

4. 路由参数

路由参数包括:1. 动态路由参数(以冒号标注的参数);2. URL参数(http://xxx.html/?a=1&b=2)。node

let UserParams = {
    template: "<div>动态路由参数页面</div>",
    created() {
        // VueRouter引入以后,Vue实例上会挂载有$router、$route两个属性对象,
        // 组件会继承Vue实例上的$router、$route对象;经过这两个对象,能够在组件内部得到路由参数。
        console.log(this.$router);
        console.log(this.$route.params)
    }
};
let UserQuery = {
    template: "<div>URL参数页面</div>"
};

// 建立router对象
var router = new VueRouter({
    routes: [
        {
            name: "UserParams",
            path: "/user/:id",  // 动态路由参数,以冒号开头
            component: UserParams
        },
        {
            name: "UserQuery",
            path: "/UserQuery",
            component: UserQuery
        }
    ]
});

let App = {
    // 两种路由参数传入 router-link 的示例:
    // 动态路由参数经过 params 属性选项传入参数;URL参数经过 query 属性选项传入参数。
    template: `
        <div>
            <router-link :to="{name: 'UserParams', params: {id: 2}}">动态路由参数</router-link>
            <router-link :to="{name: 'UserQuery', query: {userid: 3}}">URL参数</router-link>
            <router-view></router-view>
        </div>
    `
};

new Vue({
    el: "#app",
    components: {
        App
    },
    router: router,
    template: "<App/>"
})

当使用路由参数时,例如从/user/foo导航到/user/bar,原来的组件实例会被复用。由于两个路由都渲染同一个组件,比起销毁再建立,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会再被调用react

若是在复用组件时,想对路由参数的变化做出响应的话,能够简单地 watch (监测变化) $route 对象:webpack

const User = {
  template: '...',
  watch: {
    '$route' (to, from) {
      // 对路由变化做出响应...
    }
  }
}

或者使用 2.2 中引入的 beforeRouteUpdate 导航守卫:ios

const User = {
  template: '...',
  beforeRouteUpdate (to, from, next) {
    // react to route changes...
    // don't forget to call next()
  }
}

5. 路由组件传参

经过路由组件传参,能够实现同一组件根据参数的不一样显示不一样的内容,达到组件的复用。详见vue-router官方网站

6. 嵌套路由

当子路由是不一样的页面结构时,能够经过嵌套路由来根据路由加载不一样的组件。定义子路由:在路由对象router中添加children属性。

let Song = {
    template: "<div>歌曲内容页</div>"
};

let Movie = {
    template: "<div>影视内容页</div>"
};

let Home = {
    template: `
        <div>
            首页内容
            <br />
            <router-link :to="{name: 'song'}">歌曲</router-link>
            <router-link :to="{name: 'movie'}">影视</router-link>
            <router-view></router-view>
        </div>
    `
};

// 建立router对象
var router = new VueRouter({
    routes: [
        {
            name: "home",
            path: "/home",
            component: Home,
            children: [
                {
                    name: 'song',
                    path: 'song',
                    component: Song
                },
                {
                    name: 'movie',
                    path: 'movie',
                    component: Movie
                }
            ]
        }
    ]
});

let App = {
    // 两种路由参数传入 router-link 的示例
    template: `
        <div>
            <router-link :to="{name: 'home'}">首页</router-link>
            <router-view></router-view>
        </div>
    `
};

new Vue({
    el: "#app",
    components: {
        App
    },
    router: router,
    template: "<App/>"
})

7. keep-alive 在路由中的使用

内置组件keep-alive能够将组件的状态缓存,当路由切换后能够保持路由时加载的组件的状态。

let Timeline = {
        template: "<div><h3>这是首页组件</h3></div>",
        created() { console.log('首页组件建立了'); },
        mounted() { console.log('首页组件DOM加载了'); },
        destroyed() { console.log('首页组件销毁了'); }
    };
    let Pins = {
        template: "<div><h3 @click="clickHandler">这是沸点组件</h3></div>",
        methods: {
          clickHandler(e) { e.target.style.color = 'red'; }
        },
        created() { console.log('沸点组件建立了'); },
        mounted() { console.log('沸点组件DOM加载了'); },
        destroyed() { console.log('沸点组件销毁了'); }
    };

    let router = new VueRouter({
        routes: [
            {
                path: '/timeline',
                component: Timeline
            },
            {
                path: '/pins',
                component: Pins
            }
        ]
    });

    let App = {
        template: `
            <div>
                <router-link to="/timeline">首页</router-link>
                <router-link to="/pins">沸点</router-link>
                <keep-alive>
                    <router-view></router-view>
                </keep-alive>
            </div>
        `
    };

    new Vue({
        el: "#app",
        router,
        components: {App},
        template: "<App/>"
    })

8. 在路由中经过 meta 进行权限控制

示例代码知识点总结:

  • 能够将某些数据保存到本地的 localStorage 中。
  • 在方法中,能够经过编程式路由跳转到指定页面。
  • 给路由设置meta属性,以规定该路由是否须要权限验证。
  • 在全局前置导航守卫中执行路由权限验证的逻辑。
  • 必须调用全局前置导航守卫中的next()方法,不然页面不会跳转。
let Home = {template: "<div>这是首页</div>"};
let Blog = {template: "<div>这是博客</div>"};
let Login = {
    data() {
        return {name: "", passwd: ""}
    },
    template: `
        <div>
            <input type="text" v-model="name">
            <input type="password" v-model="passwd">
            <input type="button" value="登陆" @click="loginHandler">
        </div>
    `,
    methods: {
        loginHandler() {
            // 将数据保存到本地的 localStorage 中,以模拟登陆
            localStorage.setItem("user", {name: this.name, passwd: this.passwd});
            // 经过编程式导航跳转到目标页面
            this.$router.push({
                name: "blog"
            })
        }
    }
};

const router = new VueRouter({
    routes: [
        {
            path: "/",
            redirect: "/home"
        },
        {
            path: "/home",
            component: Home
        },
        {
            path: "/blog",
            name: "blog",
            component: Blog,
            // 给路由作权限控制
            meta: {
                // 规定这个路由是否须要登陆
                authValidate: true
            }
        },
        {
            path: "/login",
            name: "login",
            component: Login
        }
    ]
});
router.beforeEach((to, from, next) => {
    console.log(to);
    console.log(from);
    // 经过目的路由的meta属性来判断组件是否设定了权限验证
    if (to.meta.authValidate) {  // 路由到有登陆验证的组件时执行
        if (localStorage.getItem("user")) {  // 判断是否已经登陆,若已登陆,则直接放行
            next();
        } else {
            next({  // 若未登陆,则跳转到登陆页面
                path: '/login'
            });
        }
    } else {  // 路由到没有登陆验证的组件时执行
        if (localStorage.getItem("user")) {
            if (to.name === "login") {
                console.log(to.name);
                next({
                    path: "/home"
                })
            }else {
                next();
            }
        } else {
            next();
        }
    }
});

new Vue({
    el: "#app",
    router,
    template: `
        <div>
            <router-link to="/home">首页</router-link>
            <router-link to="/blog">个人博客</router-link>
            <router-link to="/login">登陆</router-link>
            <a href="javascript: void(0)">退出</a>
            <router-view></router-view>
        </div>
    `
})

9. 导航完成以后异步获取数据

需求:在导航完成以后加载数据,渲染DOM

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue-router在导航完成后获取数据</title>
</head>
<body>
<div id="app"></div>
<script src="node_modules/vue/dist/vue.js"></script>
<script src="node_modules/vue-router/dist/vue-router.js"></script>
<script src="node_modules/axios/dist/axios.js"></script>
<script>
    // 导航完成后获取数据,这让咱们有机会在数据获取期间展现一个loading状态,还能够在不一样视图间展现不一样的loading状态。
    var Index = {
        template: "<div>我是首页</div>"
    };
    var Post = {
        data() {
            return {
                loading: false,
                error: null,
                post: null
            }
        },
        template: `
            <div>
                <div class="loading" v-if="loading">
                    loading ...
                </div>
                <div class="error" v-if="error">
                    {{error}}
                </div>
                <div class="content" v-if="post">
                    <h2>{{post.title}}</h2>
                    <p>{{post.body}}</p>
                </div>
            </div>
        `,
        created() {
            // 组件建立完成后获取数据,此时data已经被监听了
            this.fetchData();
        },
        // watch: {
        //     "$route": 'fetchData'
        // },
        methods: {
            fetchData(){
                console.log("method fetchData is run");
                this.error = null;
                this.post = null;
                this.loading = true;
                this.$axios.get("https://jsonplaceholder.typicode.com/posts/2")
                    .then(res=> {
                        this.loading = false;
                        console.log(res.data);
                        this.post = res.data;
                    })
                    .catch(err=> {
                        this.err = err.toString();
                    })
            }
        }
    };
    var router = new VueRouter({
        routes: [
            {
                path: '/index',
                name: 'index',
                component: Index
            },
            {
                path: '/post',
                name: 'post',
                component: Post
            }
        ]
    });

    var App = {
        template: `
            <div>
                <router-link :to="{name: 'index'}">首页</router-link>
                <router-link :to="{name: 'post'}">个人博客</router-link>
                <router-view></router-view>
            </div>
        `
    };

    Vue.prototype.$axios = axios;
    var ap = new Vue({
        el: "#app",
        data: { },
        components: { App },
        template: '<App/>',
        router
    });
</script>
</body>
</html>

10. 导航守卫之在导航完成前获取数据

vue-router导航守卫官方文档
有三种方法实现导航完成前获取数据:

  1. 经过vue-router全局守卫beforeEach;
  2. 经过watch属性侦听$route的变化;
  3. 经过vue-router的组件内守卫beforeUpdate
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue-router导航守卫之在导航完成前获取数据</title>
</head>
<body>
<div id="app"></div>
<script src="node_modules/vue/dist/vue.js"></script>
<script src="node_modules/vue-router/dist/vue-router.js"></script>
<script src="node_modules/axios/dist/axios.js"></script>
<script>
    Vue.use(vueRouter);
    var User = {
        data() {
            return {
                user: '',
                error: null,
                msg: '',  // 输入框中输入的内容
                msg1: '',  // 页面中显示的数据
                confir: true
            }
        },
        template: `
            <div>
                <input type="text" v-model="msg">
                <p>{{msg1}}</p>
                <button>保存</button>
                <div v-if="error" class="error">
                    {{error}}
                </div>
                <div class="user" v-if="user">
                    <h2>{{user}}</h2>
                </div>
            </div>
        `,
        methods: {
            setDatas(data) {
                this.user = data;
            },
            setError(err) {
                this.error = err;
            },
            saveData(){
                this.msg1 = this.msg;
                this.msg = '';
                this.confir = true
            }
        },
        beforeRouteEnter(to, from, next) {
            // 在渲染该组件的对应路由被 confirm 前调用
            // 不!能!获取组件实例 `this`
            // 由于当守卫执行前,组件实例还没被建立
            axios.get('http://127.0.0.1:8080/user/${to.params.id}')
                .then(res => {
                    next(vm => {
                        vm.setDatas(res.data)
                    });
                })
                .catch(err => {
                    next(vm => vm.setError(err))
                })
        },
        beforeRouteUpdate(to, from, next) {
            // 在当前路由改变,可是该组件被复用时调用
            // 举例来讲,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
            // 因为会渲染一样的 Foo 组件,所以组件实例会被复用。而这个钩子就会在这个状况下被调用。
            // 能够访问组件实例 `this`
            this.user = null;
            this.$axios.get('http://127.0.0.1:8080/user/${to.params.id}')
                .then(res => {
                    this.setDatas(res.data);
                    next();
                })
                .catch(err => {
                    this.setError(err);
                    next();
                });
            next();
        },
        beforeRouteLeave(to, from, next) {
            // 导航离开该组件的对应路由时调用
            // 能够访问组件实例 `this`
            // 示例代码:离开组件前检查用户的输入是否保存
            if (this.msg && this.confir === true) {
                // 提示用户保存信息
                this.confir = confirm('请保存数据');
                next(false)  // 表示不放行路由;但必须加这句代码,不然会阻塞
            }else {
                next();
            }
        }
    };
    var Test = {
        template: '<div>这是测试组件</div>'
    };

    // 路由设置
    var router = new VueRouter({
        routes: [
            {
                path: '/user/:id',
                name: 'user'
            },
            {
                path: '/test',
                name: 'test',
                component: Test
            }

        ]
    });
    // 入口组件
    var App = {
        template: `
            <div>
                <router-link :to="{name: 'test'}">测试</router-link>
                <router-link :to="{name: 'user', params: {id: 1}}">用户1</router-link>
                <router-link :to="{name: 'user', params: {id: 2}}">用户2</router-link>
                <router-view></router-view>
            </div>
        `
    }

    Vue.prototype.$axios = axios;
    new Vue({
        el: "#app",
        data: {},
        components: {App},
        template: '<App/>',
        router
    })
</script>
</body>
</html>

11. 去除 URL 中的 "#"

HTML5 History 模式官网介绍
vue-router 默认使用 hash 模式,因此在路由加载的时候,项目中的 url 会自带"#"。若是不想使用"#",可使用 vue-router 的另外一种模式:history。
mode说明:
默认值:"hash"(浏览器)或"abstract"(node.js)
可选值:"hash"|"history"|"abstract"

new Router({
    mode: "history",
    base: xxx,
    routes
})

当使用 history 模式时,因为项目是单页面应用,因此在路由跳转的时候,可能因为访问不到资源而出现 404。解决办法是在服务端增长一个覆盖全部状况的候选资源:若是 URL 匹配不到任何资源,则返回 index.html 页面。

12. 路由重定向

路由重定向的详细教程能够阅读 vue-router官网-重定向和别名

13. 滚动行为

滚动行为只有在 vue-router 的history模式下才起做用。详细教程能够阅读 VueRouter 官网-滚动行为
以下是一个简单的示例:使用 vue-cli 建立项目,而后编辑 /src/router/index.js 文件:

import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/components/Home'
import About from '@/components/About'

Vue.use(Router);

export default new Router({
  mode: 'history',
  scrollBehavior(to, from, savedPosition) {
    // 只有调用了history.pushState()才会触发scrollBehavior方法。
    // return 指望滚到到哪一个的位置

    // savedPosition对象,只有在用户点击了前进/后退按钮,
    // 或者是调用了go(-1)/forward()方法才会有值,不然这个对象为null。
    console.log(savedPosition);
    if (savedPosition){  // 判断滚动条的位置,若是存在返回历史位置,不然返回到起点。
      return savedPosition;
    } else {
      return {x:0, y: 0}
    }
  },
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home
    },
    {
      path: '/about',
      name: 'about',
      component: About
    }
  ]
})

编辑 /src/App.vue 文件:

<template>
  <div id="app">
    <router-link to="/">首页</router-link>
    <router-link to="/about">关于</router-link>
    <router-view/>
  </div>
</template>
<script>
    export default {name: 'App'}
</script>
<style>
    #app {height: 2000px;}
</style>

2、axios 的使用

axios 详细资料能够参考axios 中文文档

axios做为局部模块时,为了使用,须要先进行挂载,挂载的方法有两种:

  1. 使用Vue.use();的方式挂载。
  2. 使用Vue.prototype.$axios = axios;的方式挂载。

1. 基本使用

(1) 简单 GET 请求

var App = {
    template: "<div><button @click='getData'>获取数据</button></div>",
    methods: {
        getData() {
            this.$axios.get("http://jsonplaceholder.typicode.com/todos")  // GET请求
                .then(res => {  // 请求成功的处理逻辑
                    console.log(res.data[0]);
                })
                .catch(err => {  // 请求失败的处理逻辑
                    console.log(err);
                })
        }
    }
};

Vue.prototype.$axios = axios;  // 将axios挂载到Vue实例
new Vue({
    el: "#app",
    template: '<App/>',
    components: { App }
})

(2) 并发请求

var App = {
    data() {
        return {
            getRes: "",
            postRes: ""
        }
    },
    template: `
        <div>
            <div>GET请求响应:{{getRes}}</div>
            <div>POST请求响应:{{postRes}}</div>
            <button @click="concurrentRequest">并发请求</button>
        </div>
    `,
    methods: {
        concurrentRequest() {
            this.$axios.defaults.baseURL = "http://jsonplaceholder.typicode.com/";   // 设置请求的baseURL
            let getReq = this.$axios.get("posts/55");   // GET请求
            let postReq = this.$axios.post("posts", "variable=helloWorld");   // POST请求

            this.$axios.all([getReq, postReq])
                .then(this.$axios.spread((res1, res2) => {
                    this.getRes = res1.data;
                    this.postRes = res2.data;
                }))
                .catch(err => {   // 任意一个请求失败都将致使全部请求不成功
                    console.log(err);
                })
        }
    }
};

Vue.prototype.$axios = axios;  // 挂载axios到Vue实例
new Vue({
    el: "#app",
    template: '<App/>',
    components: { App }
})

2. axios 请求配置

var App = {
    template: `
        <div>
            <button @click="getData">获取数据</button>
        </div>
    `,
    methods: {
        getData() {
            this.$axios.defaults.baseURL = "http://jsonplaceholder.typicode.com/posts/";
            this.$axios.get('', {
                params: {id: 10},  // URL参数
                transformResponse: [  // 请求返回后,执行then/catch以前,修改响应数据
                    function (data) {
                        console.log("修改以前:", data);  // 接收到的data是JSON字符串,能够经过JSON.parse()方法解析成对象
                        data = JSON.parse(data);
                        data[0].title = "Hello World";
                        return data;
                    }
                ]
            })
                .then(res => {  // 请求返回的数据若是不通过transformResponse解析成对象,res在.then中也会被自动解析成对象
                    console.log(res.data);
                })
                .catch(err => {
                    console.log(err);
                });
            this.$axios.post('', "name=Jack", {
                transformRequest: [  // 请求发送以前执行,能够修改请求将要提交的数据。只能用于PUT、POST、PATCH请求中
                    function (data) {
                        console.log("修改以前:", data);
                        data = "name=Rose";
                        return data;
                    }
                ]
            })
                .then(res => {
                    console.log(res.data);
                })
                .catch(err => {
                    console.log(err);
                })
        }
    }
};

Vue.prototype.$axios = axios;  // 挂载 axios
new Vue({
    el: "#app",
    template: '<App/>',
    components: {App}
})

3. axios 拦截器

在请求或响应被thencatch处理前能够拦截它们,而后进行业务逻辑处理。
示例一:模拟登陆

var App = {
        template: "<div><button @click='sendRequest'>发送请求</button></div>",
        methods: {
            sendRequest() {
                // 添加请求拦截器
                this.$axios.interceptors.request.use(config => {
                    console.log(config);
                    // 模拟获取cookie登陆状态,并修改请求URL
                    let userId = localStorage.getItem("userId");
                    if (userId) { config.url = "65"; }
                    return config;
                }, function (err) {
                    return Promise.reject(err);
                });
                // 添加响应拦截器
                this.$axios.interceptors.response.use(response => {
                    console.log(response.data);
                    // 模拟登陆,返回cookie
                    if (response.data.userId === 6) {
                        localStorage.setItem('userId', response.data.userId)
                    }
                    return response;
                }, function (err) {
                    return Promise.reject(err);
                });

                this.$axios.defaults.baseURL = "http://jsonplaceholder.typicode.com/posts/";
                this.$axios.get("55")
                    .then(res => { console.log(res); })
                    .catch(err => { console.log(err); })
            }
        }
    };

    Vue.prototype.$axios = axios;
    new Vue({
        el: "#app",
        components: {App},
        template: "<App/>"
    })

示例二:数据加载动画

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>VueRouter示例</title>
    <script src="./node_modules/vue/dist/vue.js"></script>
    <script src="./node_modules/axios/dist/axios.js"></script>
    <style>
        .loading {
            width: 80px;
            height: 40px;
            margin: 0 auto;
            margin-top: 100px;
        }

        .loading span {
            display: inline-block;
            width: 8px;
            height: 100%;
            border-radius: 4px;
            background: lightgreen;
            -webkit-animation: load 1s ease infinite;
        }

        @-webkit-keyframes load {
            0%, 100% {
                height: 40px;
                background: lightgreen;
            }
            50% {
                height: 70px;
                margin: -15px 0;
                background: lightblue;
            }
        }

        .loading span:nth-child(2) {
            -webkit-animation-delay: 0.2s;
        }

        .loading span:nth-child(3) {
            -webkit-animation-delay: 0.4s;
        }

        .loading span:nth-child(4) {
            -webkit-animation-delay: 0.6s;
        }

        .loading span:nth-child(5) {
            -webkit-animation-delay: 0.8s;
        }
    </style>
</head>
<body>
<div id="app"></div>
<script>
    let App = {
        data() {
            return {
                isShow: false,
            }
        },
        template: `
            <div>
                <div class="loading" v-show="isShow">
                    <span></span>
                    <span></span>
                    <span></span>
                    <span></span>
                    <span></span>
                </div>
                <button @click="sendAjax">数据获取</button>
            </div>
        `,
        methods: {
            sendAjax() {
                // 添加请求拦截器
                this.$axios.interceptors.request.use((config) => {
                    this.isShow = true;
                    return config;
                }, function (error) {
                    return Promise.reject(error);
                });
                // 添加响应拦截器
                this.$axios.interceptors.response.use((response) => {
                    this.isShow = false;
                    return response;
                }, function (error) {
                    return Promise.reject(error);
                });
                // 发送请求,获取数据
                this.$axios.get("http://jsonplaceholder.typicode.com/todos")
                    .then(res => {
                        console.log(res.data.length);
                    })
                    .catch(error => {
                        console.log(error);
                    })
            }
        }
    };

    Vue.prototype.$axios = axios;
    new Vue({
        el: "#app",
        template: '<App/>',
        components: {App}
    })
</script>
</body>
</html>

3、Vuex的使用

1. 基本介绍

Vuex的详细使用教程能够阅读 Vuex 官方网站
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的全部组件的状态,利用 Vue.js 的数据响应机制来进行高效的状态更新。全部的组件均可以从 Vuex 获取状态,以实现组件间数据的传递。

若是应用够简单,最好不要使用 Vuex,一个简单的store模式就足够了。可是若是须要构建的是一个大型单页面应用,你可能会考虑如何更好得在组件外部管理状态,Vuex 会是最好的选择。

Vuex 的五大核心概念:State、Getter、Mutation、Action、Module。

  • State:用于存储状态
  • Getter:至关于计算属性
  • Mutation:惟一修改 State 的方法就是提交 Mutation
  • Action:异步操做提交 Mutation
  • Module:将 Vuex 的状态划分红不一样的模块

Vuex 应用的核心就是store,它实际上就是一个容器,包含着应用中大部分的状态(State)。Vuex 和单纯的全局对象有两点不一样:

  1. Vuex 的状态存储都是响应式的,当 Vue 组件从store中读取状态的时候,若store中的状态发生变化,那么组件也会相应地获得高效更新。
  2. 不能直接改变store中的状态,改变store中的状态的惟一途径就是显式地提交 Mutation 。这样使得咱们能够方便地跟踪每个状态的变化。

修改 state 的惟一方法是提交 mutations ,可是 mutations 中的方法是同步的。Vuex 能够经过 actions 提交 mutations 以达到异步的效果。

2. 注意事项

Vuex 的store中的状态是响应式的,因此在 Mutation 中向 State 动态添加属性时,也须要使用 Vue 的手动设置方法完成响应式。

在 Mutation 也须要与使用 Vue 同样遵照一些注意事项:
(1) 最好提早在 store 中初始化好全部须要的属性
(2) 当须要在对象上动态添加新属性时,应该使用Vue.set(property, key, value)

使用 Vuex 时,别忘了将 Vuex 的实例化对象做为属性添加到 Vue 对象中,不然 Vuex 将不起做用。

3. 使用示例

4、webpack 入门

1. 安装

  1. 执行命令npm init初始化;
  2. 执行命令npm install webpack@3.12.0 -D下载webpack

2. 简单使用

手动实现一个简易vue-cli脚手架工具,同时学习webpack的使用。

(1) 建立index.html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>
    <div id="app"></div>
    <script src="./dist/build.js"></script>
</body>
</html>

(2) 建立main.js做为项目的入口文件

// ECMAScript6的模块导入
import Vue from "vue/dist/vue"
import App from "./App.js"
import {num1, num2, add} from "./App.js"

// 导入模块时,还能够: import * as app from "./App.js"
// 在调用时,经过: app.num1; app.add; app.default

console.log(num1, num2);
console.log(add(3, 6));

new Vue({
    el: "#app",
    components: {App},
    template: "<App/>"
})

(3) 建立App.js组件文件

var app = {
    template: "<div>程序入口组件</div>"
};
// 三种抛出方式
export default app;  // 直接抛出
export var num1= 1;  // 声明并抛出
var num2 = 2; export {num2};  // 先声明,再抛出

export function add(x, y) {  // 抛出一个函数
    return x + y;
}

(4) 打包

1. 若是 npm 全局安装 webpack,能够执行命令`webpack ./main.js ./dist/build.js`。
2. 若是`webpack`安装在项目目录,能够按以下进行配置使用:
- 设置"package.json"文件`scripts`属性"build": "webpack ./main.js ./dist/build.js";
- 执行命令`npm run build`进行打包。

(5) build.js文件解读

build.js 文件中有"0~6"注释的编号,它们分别是:

  • 0: 设置一个全局变量,在 web 端指向window对象;
  • 1: 载入main.js的代码,一个Vue实例对象;
  • 2: 载入vue源码自己;
  • 3,4,5: 都是与node_modules/setimmediate(Vue 的 DOM 异步更新)相关;
  • 6: 与App.js解析相关。

3. webpack 打包执行顺序

  1. 把全部模块的代码放到函数中,用一个数组保存起来;
  2. 根据require时传入的数组索引,能知道须要哪一段代码;
  3. 从数组中,根据索引取出包含咱们代码的函数;
  4. 执行该函数,传入一个对象module.exports
  5. 咱们的代码,按照约定,正好是用module.exports = 'xxx'进行赋值;
  6. 调用函数结束后,module.exports从原来的空对象,就有值了;
  7. 最终return module.exports;做为require函数的返回值。

4. webpack 配置文件

webpack 能够以经过指定配置文件的方式去执行打包。

  • 当全局安装webpack,且配置文件名称为预设的webpack.config.js时,能够经过执行命令: webpack打包;
  • 当全局安装webpack,但配置文件名称非预设时,能够经过执行命令: webpack --config <配置文件路径>打包。
  • 当非全局安装webpack,能够将打包命令webpack --config <配置文件路径>写入到 package.json 文件scripts属性中。

webpack 配置文件说明:

var path = require('path')  // node.js语句

module.exports = {
    // 入口
    entry: {
        // 能够有多个入口,也能够只有一个
        // 若是只有一个,就默认从这个入口开始解析
        "main": "./main.js"
    },
    output: {
        path: path.resolve('./dist'),  // 相对路径转绝对路径
        filename: "./build.js"
    },
    watch: true  // 监视文件改动,自动打包成build.js
};

5、webpack 解析器和插件

webpack 在打包过程当中遇到各类不一样的文件时,会须要不一样的解析器去解析相应的文件。例如:遇到.css文件时,须要用到css-loaderstyle-loader。解析器须要配置到webpack配置文件的module属性里。

1. CSS 文件处理

  • ES6模块导入语法:.css文件的导入语句是import 'xxx.css'
  • 解析器下载:在命令行窗口执行命令npm i css-loader style-loader -D下载。
  • 配置webpack配置文件:
var path = require('path')

module.exports = {
    entry: {
        "main": "./main.js"
    },
    output: {
        path: path.resolve('./dist'),
        filename: "./build.js"
    },
    // 声明模块 包含各个loader
    module: {
        loaders: [
            {   // 添加处理css文件的loader
                test: /\.css$/,
                loader: 'style-loader!css-loader'  // 先用css-loader解析,后用style-loader载入
            }
        ]
    },
    watch: true
};

webpack 在打包过程当中,遇到.css文件,会先用css-loader解析器去解析这个文件,而后用style-loader解析器生成 style 标签,并放到 head 标签里。

http://www.developcls.com/qa/dc6c6910a4b2495082405072a14fe246.html

2. less 文件处理

  • ES6模块导入语法:.less文件的导入语句是import 'xxx.less'
  • less 模块下载:在命令行执行命令npm i less -D下载。
  • 解析器下载:在命令行窗口执行命令npm i less-loader -D下载。
  • 配置webpack配置文件:
var path = require('path')

module.exports = {
    entry: {
        "main": "./main.js"
    },
    output: {
        path: path.resolve('./dist'),
        filename: "./build.js"
    },
    module: {
        loaders: [
            {   // 添加处理css文件的loader
                test: /\.css$/,
                loader: 'style-loader!css-loader'
            },
            {   // 添加处理less文件的loader
                test: /\.less$/,
                loader: 'style-loader!css-loader!less-loader'
            }
        ]
    },
    watch: true
}

3. 图片文件处理

  • ES6模块导入语法:图片文件的导入语句是import imgSrc from 'xxx.jpg'
  • 解析器下载:在命令行窗口执行命令npm i url-loader file-loader -D下载。
  • 配置webpack配置文件:
module.exports = {
    entry: {"main": "./main.js"},
    output: {filename: "./dist/build.js"},
    // 声明模块 包含各个loader
    module: {
        loaders: [
            {   // css文件处理
                test: /\.css$/,
                loader: 'style-loader!css-loader'
            },
            {   // less文件处理
                test: /\.less$/,
                loader: 'style-loader!css-loader!less-loader'
            },
            {   // 图片文件处理
                test: /\.(jpg|png|jpeg|gif|svg)$/,
                loader: 'url-loader?limit=4000'
            }
        ]
    }
};

图片大小比limit设置的值小时,html 页面中会使用base64编码载入图片,这能够减小图片的网络请求;图片大小比limit设置的值大时,会生成一个图片副本,html 页面中图片的路径指向该副本,图片副本会和 html 页面混在一块儿,致使项目的代码结构混乱;所以设置一个合理的limit值是颇有必要的。

特别说明:
webpack 最终会将各个模块打包成一个文件,所以样式中的url路径是相对于入口 html 页面的,而不是相对于原始 CSS 文件所在路径的,这就会致使引入失败。这个问题是经过配置file-loader解决的,file-loader能够解析项目中的url引入(不只限于 CSS 文件),而后根据配置将文件复制到相应的路径,修改打包后文件的引用路径。

4. html 文件插件

  • 插件下载:在命令行窗口执行命令npm i html-webpack-plugin --save-dev下载。
  • 配置webpack配置文件:
var path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');  // 载入插件对象

module.exports = {
    entry: {
        "main": "./src/main.js"
    },
    output: {
        path: path.resolve('./dist'),
        filename: "./build.js"
    },
    module: {
        loaders: [
            {
                test: /\.css$/,
                loader: 'style-loader!css-loader'
            },
            {
                test: /\.less$/,
                loader: 'style-loader!css-loader!less-loader'
            },
            {
                test: /\.(jpg|png|jpeg|gif|svg)$/,
                loader: 'url-loader?limit=400000'
            }
        ]
    },
    // 声明插件
    plugins: [
        new HtmlWebpackPlugin({  // 生成html文件的插件
            template: './src/index.html'  // html源文件
        })
    ],
    watch: true
};

5. webpack-dev-server 热加载插件

  • 插件下载:在命令行窗口执行命令npm install webpack-dev-server --save-dev下载。
  • 经常使用配置参数:
    • --open 自动打开浏览器
    • --hot 热更新,不刷新替换 css 样式
    • --inline 自动刷新
    • --port 指定端口
    • --process 显示编译进度
  • webpack-dev-server插件的配置,须要写在package.json文件中:
{
  "scripts": {
    "dev": "webpack-dev-server --open --hot --inline --config ./webpack.dev.config.js"
  }
}

6. ES6 语法解析

  • 模块下载:在命令行执行命令npm i babel-core babel-loader babel-preset-dev babel-plugin-transform-runtime -D
  • 配置webpack配置文件:
var path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');  // 载入插件对象

module.exports = {
    entry: {
        "main": "./src/main.js"
    },
    output: {
        path: path.resolve('./dist'),
        filename: "./build.js"
    },
    module: {
        loaders: [
            {    // css文件处理
                test: /\.css$/,
                loader: 'style-loader!css-loader'
            },
            {    // less文件处理
                test: /\.less$/,
                loader: 'style-loader!css-loader!less-loader'
            },
            {    // 图片文件处理
                test: /\.(jpg|png|jpeg|gif|svg)$/,
                loader: 'url-loader?limit=400000'
            },
            {
                // 处理ES6,7,8
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: '/node_modules/',  // 排除对node_modules的解析
                options: {
                    presets: ['env'], // 处理关键字
                    plugins: ['transform-runtime']  // 处理函数
                }
            }
        ]
    },
    // 声明插件
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html'  // html源文件
        })
    ],
    watch: true
};

ES6 语法解析模块介绍:
1)babel-core
babel-core 的做用是把 js 代码分析成 ast(抽象语法树),方便各个插件分析语法进行相应的处理。有些新语法在低版本 js 中是不存在的,如箭头函数、rest 参数,函数默认值等,这种语言层面的不兼容只能经过将代码转为 ast,分析其语法后再转为低版本 js。
2)babel-loader
babel-core 会使用 abel 转译器,abel 转译器提供了 babel 的转译API,如 babel.transform 等,用于对代码进行转译。abel 转译器经过 babel-loader 调用这些 API 来完成将 ES6 代码进行转译。因此 babel-core 和 babel-loader 须要联合使用。
3)babel-preset-env
自行配置转译过程当中使用的各种插件很是麻烦,全部 babel 官方帮咱们作了一些预设的插件集,称之为preset。这样咱们只须要使用对应的 preset 就能够了。以 JS 标准为例,babel 提供了: es201五、es201六、es201七、env。es20xx 的 preset 只转译该年份批准的标准;env 代指最新的标准,包括了 latest 和 es20xx 各年份。
4)babel-plugin-transform-runtime
babel 默认只转换新的 JavaScript 语法,而不转换新的 API。像Iterator,Generator,Set,Maps,Proxy,Reflect,Symbol,Promise等全局对象,以及一些定义在全局对象上的方法(如Object.assign)都不会转译。若是想使用这些新的对象和方法,必须使用 babel-polyfill 模块,为当前环境提供一个垫片。

7. vue组件单文件引入

  • 模块下载:在命令行窗口执行命令npm install vue-loader@4.4.1 vue-template-compiler@2.5.17 -D下载。

vue-loader依赖于vue-template-compiler

  • 建立App.vue文件:
<template>
    <!-- 当前组件的HTML结构 -->
    <div>
        {{msg}}
    </div>
</template>

<script>
    // 当前组件的业务逻辑
    export default {
        name: "App",
        data(){
            return {
                msg: 'hello App.vue'
            }
        }
    }
</script>

<style scoped>
     /* 当前组件的样式 */
</style>
  • 建立入口文件main.js:
import Vue from "vue"

import App from "./App.vue"

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

Render函数是Vue2.x版本新增的一个函数。它基于 JavaScript 计算,使用虚拟 DOM 来渲染节点提高性能。经过使用createElement(h)来建立 DOM 节点,createElementrender的核心方法。Vue 编译的时候会把 template 里面的节点解析成虚拟 DOM。

  • 配置webpack配置文件:
var path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: {
        "main": "./src/main.js"
    },
    output: {
        path: path.resolve('./dist'),
        filename: "./build.js"
    },
    module: {
        loaders: [
            {
                test: /\.css$/,
                loader: 'style-loader!css-loader'
            },
            {
                test: /\.less$/,
                loader: 'style-loader!css-loader!less-loader'
            },
            {
                test: /\.(jpg|png|jpeg|gif|svg)$/,
                loader: 'url-loader?limit=400000'
            },
            {
                // 处理vue单文件组件
                test:/\.vue$/,
                loader: 'vue-loader'
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html'
        })
    ],
    watch: true
};

8. CommonsChunkPlugin 的使用

CommonsChunkPlugin 主要是用来提取第三方库和公共模块,避免首屏加载的 bundle 文件或者按需加载的 bundle 文件体积过大,从而致使加载时间过长,着实是优化的一把利器。

(1) chunk(代码块)的分类

  • webpack当中配置的入口文件(entry)是 chunk,能够理解为entry chunk
  • 入口文件以及它的依赖文件经过 code splite (代码分割)出来的也是 chunk,能够理解为children chunk
  • 经过 CommonsChunkPlugin 建立出来的文件也是 chunk,能够理解为commons chunk

(2) CommonsChunkPlugin 可配置的属性

  • name:能够是已经存在的 chunk (通常指入口文件)对应的name,那么就会把公共模块代码合并到这个 chunk 上 ;不然,会建立名字为namecommons chunk进行合并。
  • filename:指定commons chunk的文件名。
  • chunks:指定source chunk,即指定从那些 chunk 当中去找公共模块,省略该选项的时候,默认就是entry chunk
  • minChunks:既能够是数字,也能够是函数,还能够是 Infinity,具体用法和区别下面讨论。

(3) 代码块分离的三种状况

package.json中的dependences属性记录了项目中依赖的第三方库。使用模块下载命令npm install vue.js -D会将模块添加到该属性中。

示例背景说明:项目依赖第三方库 Vue.js;两个入口文件 main1.js、main2.js;入口文件都用到了自定义公共模块 common.js。
1. 不分离出第三方库和自定义公共模块
修改 webpack.config.js 配置文件

const path = require('path');

module.exports = {
    entry: {  // 多入口文件的配置
        "main1": "./src/main1.js",
        "main2": "./src/main2.js"
    },
    output: {
        path: path.resolve('./dist'),
        filename: "[name].js"  // 对应多入口的多出口配置
    },
    watch: true
};

此时,第三方库和自定义公共模块会被打包到全部入口文件中,形成代码冗余及重复加载。

2. 分离出第三方库、自定义公共模块、webpack运行文件,但他们在同一个文件中
修改 webpack.config.js 配置文件,新增一个入口文件 vendor,并添加 CommonsChunkPlugin 插件进行模块提取分离:

const path = require('path');
const webpack = require('webpack');  // 导入webpack运行文件
const packagejson = require('./package.json');  // 导入项目package.json文件

module.exports = {
    entry: {  // 多入口文件的配置
        "main1": "./src/main1.js",
        "main2": "./src/main2.js",
        "vendor": Object.keys(packagejson.dependencies)  // 获取生产环境依赖的库
    },
    output: {
        path: path.resolve('./dist'),
        filename: "[name].js"  // 对应多入口的多出口配置
    },
    watch: true,
    plugins: [
        new webpack.optimize.CommonsChunkPlugin({  // 模块提取分离到vendor.js文件中
            name: ['vendor'],
            filename: '[name].js'
        })
    ]
};

此时第三方库、自定义公共模块、webpack运行文件被分离到同一个文件中。可是每次打包时,webpack 运行文件都会变,若是不分离出 webpack 运行文件,每次打包生成 vendor.js 对应的哈希值都会变化,使浏览器认为缓存的 vendor.js失效,而从新去服务器中获取。

3. 单独分离第三方库、自定义公共模块、webpack运行文件,它们各自在不一样文件中
第一步:抽离 webpack 运行文件
修改 webpack.config.js 配置文件

plugins: [
        new webpack.optimize.CommonsChunkPlugin({
            name: ['vendor', 'runtime'],  // runtime为抽离的webpack运行文件的名字,名字是固定的
            filename: '[name].js'
        })
    ]

上面这段代码等价于下面这段代码:

plugins: [
        new webpack.optimize.CommonsChunkPlugin({
            name: 'vendor',
            filename: '[name].js'
        }),
        new webpack.optimize.CommonsChunkPlugin({  // 用于抽离webpack运行文件
            name: 'runtime',
            filename: '[name].js',
            chunks: ['vendor']  // 从哪里抽离,即"source chunks"是谁
        })
    ]

这段抽离 webpack 运行文件的代码的意思是:建立一个名为 runtime 的 commons chunk 进行 webpack 运行文件的抽离,其中source chunks是 vendor.js。

第二步:抽离第三方库和自定义公共模块
从第三方库中分离自定义公共模块,必须定义minChunks属性才能成功抽离。minChunks 能够设置为数字、函数和 Infinity,默认值是数字2(官方文档说默认值为入口文件的数量)。

minChunks取值:

  • 数字:模块被多少个 chunk 公共引用才被抽取出来成为commons chunk;
  • 函数:接受(module, count)两个参数,返回一个布尔值,能够在函数内进行规定好的逻辑来决定某个模块是否提取成为commons chunk
  • Infinity:只有当入口文件(entry chunks)大于 3 时才生效,用来从第三方库中分离自定义的公共模块。

修改 webpack.config.js 配置文件,要把第三方库和自定义公共模块分别单独抽离出来,首先须要将minChunks属性设置为Infinity

const path = require('path');
const webpack = require('webpack');  // 导入webpack运行文件
const packagejson = require('./package.json');  // 导入项目package.json文件

module.exports = {
    entry: {  // 多入口文件的配置
        "main1": "./src/main1.js",
        "main2": "./src/main2.js",
        "vendor": Object.keys(packagejson.dependencies)  // 获取生产环境依赖的库
    },
    output: {
        path: path.resolve('./dist'),
        filename: "[name].js"  // 对应多入口的多出口配置
    },
    watch: true,
    plugins: [
        new webpack.optimize.CommonsChunkPlugin({
            name: ['vendor', 'runtime'],
            filename: '[name].js',
            minChunks: Infinity  // 设置minChunks属性
        }),
        new webpack.optimize.CommonsChunkPlugin({
            name: 'common',
            filename: '[name].js',
            chunks: ['main1.js', 'main2.js']  // 从哪些文件中抽取commons chunk
        })
    ]
};

此时 vendor.js、第三方文件、自定义公共模块、webpack 运行文件就抽离出来,并分别在不一样文件中。

9. webpack.ensure 异步加载

webpack.ensure有人称为异步加载,也有人叫它代码切割。其实就是把 JS 模块独立导出到一个.js文件,而后在使用这个模块的时候,webpack 会构造script dom元素,由浏览器发起异步请求获取这个.js文件。

webpack.ensure 的原理:
把一些 JS 模块独立成一个个.js文件,而后须要用到的时候,再建立一个script对象,加入到document.head对象中。浏览器会自动发起请求,去请求这个.js文件,再经过回调函数,去定义获得这个.js文件后,须要执行什么业务逻辑操做。

示例背景说明
main.js依赖三个js文件:
(1) A.js是封装aBtn按钮点击后才执行的业务逻辑;
(2) B.js是封装bBtn按钮点击后才执行的业务逻辑;
(3) vue.js是封装了main.js须要利用的包。
A.js和B.js都不是main.js必须的,都是将来才可能发生的操做,那么能够利用异步加载,当发生的时候再去加载。
vue.js是main.js当即依赖的工具箱,但它又很是大,因此将其配置打包成一个公共模块,利用浏览器的并发加载,加快下载速度。

index.html 文件:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>webpack的使用</title>
</head>
<body>
    <div id="app"></div>
    <button id="aBtn">A-btn</button>
    <br>
    <button id="bBtn">B-btn</button>
</body>
</html>

main.js 文件

// ECMAScript6的模块导入
import Vue from "vue"
console.log(Vue);

document.getElementById('aBtn').onclick = function () {
    // 异步的加载A.js
    require.ensure([], function () {
        var A = require("./A.js");
        alert(A.data);
    })

};

document.getElementById('bBtn').onclick = function () {
    // 异步的加载B.js
    require.ensure([], function () {  // ensure函数的第一个参数(数组[])用于添加回调函数中异步加载的JS文件的依赖文件的路径
        var B = require("./B.js");
        alert(B.data);
    })
};

A.js & B.js

// A.js
var A = {
    "data": "Hello A"
};
module.exports = A;

// B.js
var B = {
    "data": "Hello B"
};
module.exports = B;

webpack 配置文件

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');  // 导入webpack运行文件
const packagejson = require('./package.json');  // 导入项目package.json文件

module.exports = {
    entry: {
        "main": "./src/main.js",
        "util": Object.keys(packagejson.dependencies)
    },
    output: {
        path: path.resolve('./dist'),
        filename: "[name].js"  // 对应多入口的多出口配置
    },
    watch: true,
    plugins: [
        new webpack.optimize.CommonChunkPlugin({
            name: "common",
            filename: "[name].js"
        }),
        new HtmlWebpackPlugin({
            // 主要用于多入口文件,当有多个入口文件的时候,它就会编译生成多个打包后的文件,chunks就能选择你要使用哪些JS文件
            chunks: ["common", "util", "main"],
            template: "./src/index.html",
            inject: true  // inject有四个值 true、body、head
        })
    ]
};

6、RESTful 规范

RESTful规范是一种软件的架构风格、设计风格,而不是标准,为客户端和服务端的交互提供一组设计原则和约束条件。
先后端分离:

  • 后端提供接口(API)
  • 前端写页面和Ajax技术

1. 面向资源编程

每一个URL表明一种资源,URL中尽可能不要使用动词,要用名词,每每名词跟数据库表格相对应。通常来讲,数据库中的表都是同种记录的集合,全部API中的名词也应该使用复数。
例如:一个提供动物园信息的API,包括各类动物和雇员的信息,它的路径应该设计成:

https://api.example.com/v1/zoos
https://api.example.com/v1/animals
https://api.example.com/v1/employees

RESTful规范参考

2. 在URL中的过滤条件

若是记录数量不少,服务器不可能将全部的数据都返回给用户。API应该提供参数,用于过滤返回结果。

?limit=10: 指定返回记录的数量
?offset=10: 指定返回记录的开始位置
?page=2&per_page=100: 指定第几页,以及每页的记录数
?sortby=name&order=asc: 指定返回结果按照哪一个属性排序,以及排序顺序
?item_id=1: 指定筛选条件

3. 尽可能使用HTTPS

4. 相应时设置状态码

5. 返回错误信息

若是状态码是4XX,应该向用户返回错误信息。通常来讲,返回的信息中将error做为键名,错误信息做为键值便可。

6. Hypermedia API

若是遇到须要跳转的状况,那么就要携带跳转接口的URL。
Hypermedia API 的设计,好比github的API就是这种设计。访问api.github.com就会获得一个全部可用的API的网址列表。

7. 其余

  1. API的身份认证应该使用OAuth 2.0框架
  2. 服务器返回的数据格式,应该尽可能使用JSON,避免使用XML

7、其余前端功能库补充

1. qs 库

qs 库(模块)是一个增长了一些安全性的查询字符串解析和序列化字符串的库。

 

posted @ 2020-06-24 10:44  droxy  阅读(247)  评论(0编辑  收藏  举报