Vue

一. Vue概述

1. 什么是Vue?

  • Vue是一套用于构建用户界面的渐进式框架
  • vue的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合

2. Vue:渐进式JavaScript框架

其中框架指的是提供一些基础性的服务
指的是以提供API为主
渐进式: 声明式渲染-> 组件系统->客户端路由->集中式状态管理->项目构建
官网

Vue的优点

  • 易用: 熟悉HTML、CSS、JavaScript知识后,可快速上手Vue
  • 灵活:在一个库和一套完整框架之间自如伸缩
  • 高效:20kB运行大小,超快虚拟DOM

二. Vue的基本使用

1. 使用Vue将helloworld 渲染到页面上

 <!-- Vue代码运行原理分析:
    概述编译过程的概念(vue语法->原生语法) -->


    <div id="app">
        <!-- {{}}为插值表达式-->
        <div>{{msg}}</div>
        <div>{{1 + 2}}</div>
        <div>{{msg + '----' + 133}}</div>

    </div>

    <script src="js/vue.js"></script>
    <script>
        // Vue的基本使用步骤
        // 1. 需要提供标签用于填充数据
        // 2. 引入vue.js库文件
        // 3. 可以使用vue的语法做功能了
        // 4. 把vue提供的数据填充到标签里面
        var num = new Vue({
            el: '#app',
            data: {
                msg: 'hello Vue'
            }
        })
    </script>

1. 实例参数分析

  • el: 元素的挂载位置(值可以是CSS选择器或者DOM元素)
  • data: 模型数据(值是一个对象)

2. 插值表达式用法

  • 将数据填充到HTML标签中
  • 插值表达式支持基本的计算操作

3. Vue代码运行原理分析

  • 概述编译·过程的概念(Vue语法->原生语法)

三. Vue模板语法

3.1 模板语法概述

1. 如何理解前端渲染?

把数据填充到HTML标签中

2. 前端渲染方式

  • 原生js拼接字符串
  • 使用前端模板引擎
  • 使用vue特有的模板语法

3. 原生js凭借字符串

基本上就是将数据以字符串的方式拼接到HTML标签中。

缺点:不同开发人员的代码风格差别很大,随着业务的复杂,后期的维护变得逐渐困难起来。

4. 使用前端模板引擎

优点:大家都遵循同样的规则写代码,代码可读性明显提高了,方便后期维护。

缺点:没有专门提供事件机制。

5. 模板语法概览

  • 差值表达式
  • 指令
  • 事件绑定(即事件的处理)
  • 属性绑定
  • 样式绑定
  • 分支循环结构

3.2 指令

1. 什么是指令?

  • 什么是自定义属性
  • 指令的本质就是自定义属性
  • 指令的格式: 以 v-开始 (比如: v-cloak)

2. v-cloak指令用法

  • 差值表达式存在的问题: “闪动”
  • 如何解决该问题: 使用 v-cloak 指令
  • 解决该问题的原理: 先隐藏,替换好值之后再显示最终的值

官网

3. 数据绑定指令

  • v-text 填充纯文本
    ① 相比插值表达式更加简洁
  • v-html 填充HTML片段
    ① 存在安全问题
    ② 本网站内部数据可以使用,来自第三方的数据不可以使用
  • v-pre 填充原始信息
    ① 显示原始信息,跳过编译过程(分析编译过程)

4. 数据响应式

  • 如何理解响应式
    ① html5的响应式(屏幕尺寸的变化导致样式的变化)
    ② 数据的响应式(数据的变化导致页面内容的变化)
  • 什么式数据绑定
    ① 数据绑定: 将数据填充到标签中
  • v-once 只编译一次
    ① 显示内容之后不再具有响应式功能

3.3 双向数据绑定指令

1. 什么是双向数据绑定事件?(① 用户去改页面中插值表达式的值,数据也会跟着改变;② 数据发生变化,插值表达式的值也会发生变化)

2. 双向数据绑定分析

  • v-mode 指令用法
    <input type='text' v-model='uname'/>

3. MVVM设计思想

① M(model) 即data中的数据
② V(view) 即模板 (本质上来说是DOM元素)
③ VM(View-Model)实现控制逻辑

3.4 事件绑定

1. Vue如何处理事件?

  • v-on指令用法
    <input type="button" v-on:click="num++"/>

  • v-on简写形式
    `<input type="button" @click="num++"/>

2. 事件函数的调用方式

  • 直接绑定函数名称
    <button v-on:click="say">Hello</button>

  • 调用函数
    <button v-on:click="say()">Say hi</button>

3.事件函数参数传递

  • 普通参数和事件对象
    <button v-on:click="say('hi',$event)">Say hi</button>

4. 事件修饰符

  • .stop 阻止冒泡
    <a v-on:click.stop="handle">跳转</a>

  • .prevent 阻止默认行为
    <a v-on:click.prevemt="handle">跳转</a>

5. 按键修饰符

  • .enter 回车键
    <input v-on:keyup.enter="submit">
  • .esc 退出键
    <input v-on:keyup.delete="handle">

6. 自定义按键修饰符

  • 全局config.keyCodes对象
    Vue.config.keyCodes.f1=112
    规则:自定义按键修饰符名字是自定义的,但是对应的值必须是按键对应event.keyCode值

3.5 属性绑定

1. Vue如何动态处理属性?

  • v-bind指令用法
    <a v-bind:herf='url'>跳转</a>
  • 缩写形式
    `跳转

2. v-mode的底层实现原理分析

<input v-bind:value="msg" v-on:input="msg=$event.target.value">

3.6 样式绑定

1. class样式处理

  • 对象语法
    <div v-bind:class="{active: isActice}"></div>

  • 数组语法
    <div v-bind:class="{activeClass: errorClass}"></div>

样式绑定的相关语法细节:
1) 对象绑定和数组绑定可以结合使用
2)class绑定的值可以简化操作
3)默认的class如何处理? 默认的class会被保留

<body>
    <div id="app">
        <div :class="[activeClass,errorClass, {test: isTest}]">测试样式</div>
        <div :class="arrClasses">测试样式</div>
        <div :class="objClasses">测试样式</div>
        <div class="base" :class="objClasses">测试样式</div>
        <button v-on:click='handle'>切换</button>
    </div>
    <script src="js/vue.js"></script>
    <script>
        // 样式绑定相关语法细节:
        // - 对象那个绑定和数组绑定可以结合使用
        // - class绑定的值可以简化操作
        // - 默认的class如何处理? ,默认的class会被保留
        var vm = new Vue({
            el: '#app',
            data: {
                activeClass: 'active',
                errorClass: 'error',
                isTest: true,
                arrClasses: ['active', 'error'],
                objClasses: {
                    active: true,
                    error: true,

                }
            },
            methods: {
                handle: function() {
                    this.isTest = false;

                }
            }
        });
    </script>
</body>

2. style样式处理

  • 对象语法
    <div v-bind:style="[color: activerColor, fontSize: fontSize]"></div>

  • 数组语法
    <div v-bind:style="[baseStyles, overridingStyles]"></div>

3.7 分支循环结构

1. 分支结构

  • v-if
  • v-else
  • v-else-if
  • v-show
<body>
    <div id="app">
        <div v-if='score>=90'>优秀</div>
        <div v-else-if='score<90 && score>=80'>良好</div>
        <div v-else-if='score<80 && score >=60'>一般</div>
        <div v-else>较差</div>
        <div v-show='flag'>测试v-show</div>
        <button v-on:click='handle'>点击</button>
    </div>
    <script src="js/vue.js"></script>
    <script>
        // 分支结构 
        // - v-if:控制元素是否渲染到页面 (出现之后用的就比较少了,就用)
        // - v-else
        // - v-else-if
        // - v-show的原理: 控制元素的样式是否显示 display:none/block (平凡的让一个元素显示或隐藏时用)
        var vm = new Vue({
            el: '#app ',
            data: {
                score: 10,
                flag: false,
            },
            methods: {
                handle: function() {
                    this.flag = !this.flag;
                }
            }
        })
    </script>
</body>

2. v-if与v-show的区别

  • v-if 控制元素是否渲染到页面 如果平凡的让一个元素显示和隐藏则有v-if
  • v-show 控制元素是否显示(已经渲染到了页面,但有可能没有显示,是隐藏的) 控制样式的变化用v-show

3. 循环结构

  • v-for遍历数组
    <li v-for='item in list'> {{item}}</li>
    <li v-for='(item,index) in list'>{{item}} +'-----'+{{index}} </li>
  • key的作用:帮助Vue区分不同的元素,从而提高性能
    <li :key='item.id' v-for='(item,index) in list'> {{item}} + '----' + {{index}}</li>
<body>
    <div id="app">
        <div>水果列表</div>
        <ul>
            <li v-for='item in fruites'>{{item}}</li>
            <li v-for='(item,index) in fruites'>{{item +'----'+index}}</li>
            <li :key='item.id' v-for='(item,index) in myFruites'>
                <span>{{item.ename}}</span>
                <span>---------</span>
                <span>{{item.cname}}</span>
            </li>

        </ul>
    </div>
    <script src="js/vue.js"></script>
    <script>
        // 循环结构:
        // - v-for遍历数组
        // - key的作用: 帮助Vue区分不同的元素,从而提高性能 (在遍历的时候必须加上key)
        var vm = new Vue({
            el: '#app',
            data: {
                fruites: ['apple', 'orange', 'banana'],
                myFruites: [{
                    id: 1,
                    ename: 'apple',
                    cname: '苹果'
                }, {
                    id: 2,
                    ename: 'orange',
                    cname: '橘子'
                }, {
                    id: 3,
                    ename: 'banana',
                    cname: '香蕉'
                }]
            },
            methods: {

            }
        })
    </script>
</body>

运行结果为:

4. 循环结构

  • v-for遍历对象
    <div v-for='{value,key, index) in object'></div>

  • v-if和v-for结合使用
    <div v-if='value==12' v-for='(value, key, index) in object'></div>

<body>
    <div id="app">
        <div v-if='v==18' v-for='(v,k,i) in obj'>{{v +'----'+ k +'----'+ i}}</div>
    </div>
    <script src="js/vue.js"></script>
    <script>
        // 原生js遍历对象
        var obj = {
            uname: 'lisi',
            age: 18,
            sex: 'male'
        }
        for (var key in obj) {
            console.log(key, obj[key]);
        }
        var vm = new Vue({
            el: '#app',
            data: {
                obj: {
                    uname: 'lisi',
                    age: 18,
                    sex: 'male'
                }
            },
            methods: {

            }
        })
    </script>
</body>

运行结果:

四. 基础案例

五. Vue常用特性

5.1 常用特性概览

  • 表单操作
  • 自定义指令
  • 计算属性
  • 侦听器
  • 过滤器
  • 生命周期

5.2 表单操作

1. 基于Vue的表单操作

  • input 单行文本
  • textarea 多行文本
  • select 下拉对选
  • radio 单选框
  • checkbox 多选框

2. 表单域修饰符

  • number: 转换为数值
  • trim: 去掉开始和结尾的空格
  • lazy: 将input事件切换为change事件

<input v-model.number='age' type="number">

5.3 自定义指令

1. 为何需要自定义指令?

内置指令不满足需求

2. 自定义指令的语法规则(获取元素焦点)

Vue.directive('focus' {
  inserted: function(el) {
    // 获取元素的焦点
    el.focus();
  }
})

3. 自定义指令用法

<input type="text", v-focus>

4. 带参数的自定义指令(改变元素背景色)

Vue.directive(‘color', {
  inserted: function(el, binding) {
    el.style.backgroundColor = binding.value.color;
  }
})

5. 指令用法

<input type="text" v-color='{color:"orange"}'>

6. 局部指令

directives: {
  focus: {
    // 指令的定义
    inserted: function (el) {
      el.focus()
    }
  }
} 

5.4 计算属性

1. 何为需要计算属性

表达式的计算逻辑可能会比较复杂,使用计算属性可以使模板内容更加简洁

2. 计算属性的用法

computed: {
  reversedMessage: function () {
    return this.msg.split('').reverse().join('')
  }
}

3. 计算属性与方法的区别

  • 计算属性是基于它们的依赖进行缓存的
  • 方法不存在缓存
<body>
    <div id="app">
        <div>{{msg}}</div>
        <div>{{reverseMessage()}}</div>
        <div>{{reverseMessage()}}</div>
        <div>{{reverseString}}</div>
        <div>{{reverseString}}</div>
    </div>
    <script src="js/vue.js"></script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                msg: 'hello'
            },
            methods: {
                reverseMessage: function() {
                    console.log('methods');
                    return this.msg.split('').reverse().join('');
                }
            },
            computed: {
                reverseString: function() {
                    console.log('computed');
                    return this.msg.split('').reverse().join('');
                }
            }
        });
    </script>
</body>

运行结果如下:

5.5 侦听器

侦听器的应用场景

数据变化时执行异步或开销较大的操作

2. 侦听器的用法

watch: {
  firstName: function(val){
    // val表示变化之后的值
    this.fullName = val + this.lastName;
  },
  lastName: function(val) {
  this.fullName = this.firstName + val;
  }
}

5.6 过滤器

1. 过滤器的作用是什么?

格式化数据,比如将字符串格式化为首字母大写,佳能日期格式化为指定的格式等

2. 自定义过滤器

Vue.filter('过滤器名称', function(value) {
  // 过滤器业务逻辑
})

3. 过滤器的使用

<div>{{msg | upper}}</div>
<div>{{msg | upper  lower}}</div>
<div v-bind:id='id | formatId'></div>

案例:

<body>
    <div id="app">
        <input type="text" v-model='msg'>
        <div>{{msg | upper}}</div>
        <div>{{msg | upper | lower}}</div>
        <div :abc='msg | upper'>测试数据</div>
        <div :abc='msg | lower'>测试数据形式</div>
    </div>
    <script src="js/vue.js"></script>
    <script>
        // 过滤器

        // 定义过滤器
        Vue.filter('upper', function(val) {
            return val.charAt(0).toUpperCase() + val.slice(1);
        });
        Vue.filter('lower', function(val) {
            return val.charAt(0).toLowerCase() + val.slice(1);
        })
        var vm = new Vue({
            el: '#app',
            data: {
                msg: ''
            },

        })
    </script>
</body>

运行结果:

4. 局部过滤器

filters: {
  capitalize: function() {}
}

5. 带参数的过滤器

Vue.filter(‘format’, function(value, arg1){
  // value就是过滤器传递过来的参数
})

6. 过滤器的使用

<div>{{date | format(‘yyyy-MM-dd')}}</div>
日期格式化规则
y: 年,
M:年中的月份(1-12),
d: 月中的天(1-31),
h: 小时(0-23),
m: 分(0-59),
s: 秒(0-59),
S: 毫秒(0-999),
q: 季度(1-4)
案例:日期格式化

<body>
    <div id="app">
        <div>{{date | format('yyyy-MM-dd')}}</div>
    </div>
    <script src="js/vue.js"></script>
    <script>
        // 过滤器案例: 格式化日期

        // Vue.filter('format', function(val, age) {
        //     if (age == 'yyyy-MM-dd') {
        //         var ret = '';
        //         ret += val.getFullYear() + '-' + (val.getMonth() + 1) + '-' + val.getDate();
        //         return ret;
        //     }
        //     return val;
        // })

        // 日期格式化规则
        // y: 年,
        // M:年中的月份(1-12),
        // d: 月中的天(1-31),
        // h: 小时(0-23),
        // m: 分(0-59),
        // s: 秒(0-59),
        // S: 毫秒(0-999),
        // q: 季度(1-4)

        Vue.filter('format', function(value, arg) {
            function dateFormat(date, format) {
                if (typeof date === "string") {
                    var mts = date.match(/(/Date((d+))/)/);
                    if (mts && mts.length >= 3) {
                        date = parseInt(mts[2]);
                    }
                }
                date = new Date(date);
                if (!date || date.toUTCString() == "Invalid Date") {
                    return "";
                }
                var map = {
                    "M": date.getMonth() + 1, //月份 
                    "d": date.getDate(), //日 
                    "h": date.getHours(), //小时 
                    "m": date.getMinutes(), //分 
                    "s": date.getSeconds(), //秒 
                    "q": Math.floor((date.getMonth() + 3) / 3), //季度 
                    "S": date.getMilliseconds() //毫秒 
                };

                format = format.replace(/([yMdhmsqS])+/g, function(all, t) {
                    var v = map[t];
                    if (v !== undefined) {
                        if (all.length > 1) {
                            v = '0' + v;
                            v = v.substr(v.length - 2);
                        }
                        return v;
                    } else if (t === 'y') {
                        return (date.getFullYear() + '').substr(4 - all.length);
                    }
                    return all;
                });
                return format;
            }
            return dateFormat(value, arg);
        })

        var vm = new Vue({
            el: '#app',
            data: {
                date: new Date()
            }
        })
    </script>
</body>

6.1 生命周期

1. 主要阶段

  • 挂载(初始化相关属性)
    ① beforeCreate
    ② created
    ③ beforeMount
    ④ mounted

  • 更新(元素或组件的变化操作)
    ① beforeUpdate
    ② uodated

  • 销毁(销毁相关的属性)
    ① beforeDestroy
    ② destroyed

2. Vue 实例的产生过程

① beforeCreate 在实例初始化之后,数据观测和事件配置之前被调用。
② created 在实例创建完成后被立即调用。
③ beforeMount 在挂载开始之前被调用。
④ mounted el被新创建的vm.$el替换,并挂载到实例上去之后调用该钩子。
⑤ beforeUpdate 数据更新时调用,发生在虚拟DOM打补丁之前。
⑥ updated 由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子。
⑦ beforeDestroy 实例销毁之前调用。
⑧ destroyed 实例销毁后调用。

6.2 数组相关API(重点)

1. 变异方法(修改原有数据)

Vue 包含一组观察数组的变异方法,所以它们也将会触发视图更新。

  • push()
  • pop()
  • shift()
  • unshift()
  • splice() 实现删除数组中指定的元素
  • sort() 实现排序
  • reverse() 实现数组元素的翻转

2. 替换数组(生成新的数组)

  • filter()
  • concat()
  • slice()

3. 修改相应式数据

  • Vue.set(vm.item, indexOfItem, newValue)
  • vm.$set(vm.items, indexOfItem, newValue)
    ① 参数一表示要处理的数组名称
    ② 参数二表示要处理短的数组的索引
    ③ 参数三表示要处理的数组的值

原始方法:

<body>
    <div id="app">
        <ul>
            <li v-for='item in list'>{{item}}</li>
        </ul>
    </div>
    <script src="js/vue.js"></script>
    <script>
        // 动态处理响应式数据
        var vm = new Vue({
            el: '#app',
            data: {
                list: ['apple', 'orange', 'banbana']
            }
        });
        vm.list[1] = 'lemon';
    </script>
</body>

运行结果:

7. 组件化开发思想

7.1 现实中的组件化思想体现

  • 标准
  • 分治
  • 重用
  • 组合

7.2 编程中的组件化思想体现

7.3 组件化规范:Web Components

  • 我们希望尽可能多的重用代码
  • 自定义组件的方式不太容易
  • 多次使用组件可能导致冲突

Web Components 通过创建封装好的功能的定制元素解决上述问题

官网: https://developer.mozilla.org/zh-CN/docs/Web/Web_Components

8. 组件注册

8.1 全局组件注册为语法

Vue.component(组件名称, {
  data: 组件数据,
  template: 组件模板内容
})
// 注册一个名为button-counter 的新组件
Vue.component('button-counter', {
  data: function() {
    return {
      count: 0
    }
  }
trmplate: '<button v-on:click="count++">点击了{{count}}此</button>'
})

8.2 组件用法

<div id="app">
  <button-counter></button-counter>
</div>
<div id="app">
  <button-counter></button-counter>
  <button-counter></button-counter>
  <button-counter></button-counter>
</div>

8.3 组件注册注意事项

1. data必须是一个函数

  • 分析函数与普通对象的对比

2. 组件模板内容必须是一个根元素

  • 分析演示实际的效果

3. 组件模板内容可以是模板字符串

  • 模板字符串需要浏览器提供支持(ES6语法)

4. 组件命名方式

  • 短横线方式
    Vue.component('my-compontent', { /* ... */ })
  • 驼峰方式
    Vue.compontent('MyComponent', { /* ... */ })

注意事项:
如果使用驼峰式命名组件,那么在使用组建的时候,只能在字符串中用驼峰的方式使用组件,但是在普通的标签模板中,必须使用短横线的方式使用组件

8.4 局部组件注册

var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponemtC = { /* ... */ }
new Vue({
  el: '#app',
  components: {
    'component-a': ComponentA,
    'component-b': ComponentB,
    'componemt-c': ComponentC,
  }
})

局部组件只能在注册它的组件中才能使用,全局组件可以在所有的组件中使用

9. Vue 调试工具

9.1 调试工具安装

① 克隆仓库
② 安装依赖包
③ 构建
④ 打开Chrome扩展页面
⑤ 选中开发者模式
⑥ 加载已解压的扩展,选择shells/chrom

9.2 调试工具用法

10. 组件间的数据交互

10.1 父组件向子组件传值

1. 组件内部通过props 接收传递过来的值

Vue.component(‘menu-item', {
  props: ['title'],
  template: '<div>{{ title }}</div>'
})

2. 父组件通过属性将值传递给子组件

<menu-item title="来自父组件的数据"></menu-item>
<menu-item :title="title"></menu-item>

3. props属性名规则

  • 在props中使用驼峰形式,模板中需要使用短横线的形式
  • 字符串形式的模板中没有这个限制
Vue.component(‘menu-item', {
  // 在 JavaScript 中是驼峰式的
  props: [‘menuTitle'],
  template: '<div>{{ menuTitle }}</div>'
})
<!– 在html中是短横线方式的 -->
<menu-item menu-title=“nihao"></menu-item>

4. props属性值类型

  • 字符串String
  • 数值Number
  • 布尔型Boolean
  • 数组Array
  • 对象Object

10.2 子组件向父组件传值

1. 子组件通过自定义事件向父组件传递信息

<button v-on:click='$emit("enlarge-text") '>扩大字体</button>

2. 父组件监听子组件的事件

<menu-item v-on:enlarge-text='fontSize += 0.1'></menu-item>

3. 子组件通过自定义事件向父组件传递信息

<button v-on:click='$emit("enlarge-text", 0.1) '>扩大字体</button>

4. 父组件监听子组件的事件

<menu-item v-on:enlarge-text='fontSize += $event'></menu-item>

10.3 非父子组件间传值

1. 单独的事件中心管理组件间的通信

var eventHub = new Vue()

2. 监听事件与销毁事件

eventHub.$on('add-todo', addTodo)
eventHub.$off('add-todo')

3. 触发事件

eventHub.$emit(‘add-todo', id)

例子

<body>
    <div id="app">
        <div>父组件</div>
        <div>
            <button @click='handle'>销毁事件</button>
        </div>
        <test-tom></test-tom>
        <test-jerry></test-jerry>
    </div>
    <script src="js/vue.js"></script>
    <script>
        // 兄弟组件之间数据传递

        // 1. 提供事件中心
        var hub = new Vue();

        Vue.component('test-tom', {
            data: function() {
                return {
                    num: 0
                }
            },
            template: `
                <div>
                    <div>TOM:{{num}}</div>
                    <div>
                        <button @click='handle'>点击</button>
                    </div>
                </div>
            `,
            methods: {
                handle: function() {
                    // 3. 触发兄弟组件的事件
                    hub.$emit('jerry-event', 2);
                }
            },
            mounted: function() {
                // 2. 监听事件
                hub.$on('tom-event', (val) => {
                    this.num += val;
                })
            }
        });
        Vue.component('test-jerry', {
            data: function() {
                return {
                    num: 0
                }
            },
            template: `
                <div>
                    <div>JERRY:{{num}}</div>
                    <div>
                        <button @click='handle'>点击</button>
                    </div>
                </div>
            `,
            methods: {
                handle: function() {
                    hub.$emit('tom-event', 1);
                }
            },
            mounted: function() {
                hub.$on('jerry-event', (val) => {
                    this.num += val;
                })
            }
        });
        var vm = new Vue({
            el: '#app',
            data: {

            },
            methods: {
                handle: function() {
                    // 4. 销毁事件
                    hub.$off('tom-event');
                    hub.$off('jerry-event')
                }
            }
        })
    </script>
</body>

运行结果:

11. 组件插槽

11.1 组件插槽的作用

  • 父组件向子组件传递内容(其中内容指的时模板的内容)

11.2 组件插槽基本用法

1. 插槽位置

Vue.component('alert-box', {
  template: `
    <div class="demo-alert-box">
    <strong>Error!</strong>
    <slot></slot>
    </div>
  `
})

标签为固定不变的

2. 插槽内容

<alert-box>Something bad happened.</alert-box>

举例为

<body>
    <div id="app">
        <alert-box>有bug发生</alert-box>
        <alert-box>有一个警告</alert-box>
        <alert-box></alert-box>
    </div>
    <script src="js/vue.js"></script>
    <script>
        Vue.component('alert-box', {
            template: `
                <div>
                    <strong>ERROR:</strong>
                    <slot>默认内容</slot>
                </div>
            `

        })

        var vm = new Vue({
            el: '#app',
            data: {

            }
        });
    </script>
</body>

运行结果:

11.3 具名插槽用法

1. 插槽定义

<div class="container">
  <header>
    <slot name="header"><slot>
  </header>
  <main>
    <slot></slot>
  <main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

2. 插槽内容

<base-layout>
  <h1 slot="header">标题内容</h1>

  <p>主要内容1</p>
  <p>主要内容2</p>

  <p slot="footer">底部内容</p>
</base-layout>

案例:

<body>
    <div id="app">
        <base-layout>
            <h1 slot="header">标题内容</h1>
            <p>主要内容1</p>
            <p>主要内容2</p>
            <p slot="footer">底部内容</p>
        </base-layout>

        <base-layout>
            <template slot="header">
                <h1>标题内容1</h1>
                <h1>标题内容2</h1>
            </template>
            <p>主要内容1</p>
            <p>主要内容2</p>
            <template slot="footer">
                <h1>底部内容1</h1>
                <h1>底部内容2</h1>
            </template>
        </base-layout>
    </div>
    <script src="js/vue.js"></script>
    <script>
        // 具名插槽

        Vue.component('base-layout', {
            template: `
                <div>
                    <header>
                        <slot name="header"></slot>    
                    </header>
                    <main>
                        <slot></slot>
                    </main>
                    <footer>
                        <slot name="footer"></slot>
                    </footer>
                </div>
            `
        });
        var vm = new Vue({
            el: '#app',
            data: {

            }
        })
    </script>
</body>

运行结果:

11.4 作用域插槽

  • 应用场景: 父组件对子组件的内容进行加工处理

1. 插槽定义

<ul> 
  <li v-for="item in list" v-bind:key="item.id">
    <slot v-bind:item="item">
      {{item.name}}
    </slot>
  </li>
</ul>

2. 插槽内容

<fruit-list v-bind:list="list">
  <template slot-scope="slotProps">
    <strong v-if="slotProps.item.current">
      {{slotProps.item.text}}
    </strong>
  </template>
</fruit-list>

12. 前后端交互模式

12.1 接口调用方式

  • 原生 ajax
  • 基于jQuery的 ajax (侧重点为DOM操作)
  • fetch (ajax的升级版)
  • axios
    客户端和服务器的通讯模式

12.2 URL 地址格式

1. 传统形式的URL

  • 格式: schema://host:port/path?query#fragment

① schema:协议。例如http、https、ftp等
② host:域名或者IP地址
③ port:端口,http默认端口为80,可以省略
④ path:路劲,例如/abc/a/b/c (这个路劲是虚拟的,其作用为区分不同的资源)
⑤ query:查询参数,例如 uname=lisi$age=12
⑥ fragment:锚点(哈希Hash),用于定位页面的某个位置

2. Restful形式的 URL

  • HTTP请求方式

① GET 查询
② POST 添加
③ PUT 修改
④ DELETE 删除

  • 符合规定的URL地址

http://www.hello.com/books GET
http://www.hello.com/books POST
http://www.hello.com/books/123 PUT 修改id=123的这本书的信息
http://www.hello.com/books/123 DELETE 删除id=123的这本书的信息

13. Promise用法(es6)

13.1 异步调用

  • JavaScript的执行环境是单线程
  • 所谓单线程,是指JS 引擎中负责解释和执行JavaScript代码的线程只有一个,也就是一次只能完成一项任务,这个任务执行完之后才能执行下一个,它会阻塞其他任务。这个任务可称为主线程。
  • 异步模式可以一起执行多个任务
  • 异步效果分析
    ① 定时任务
    ② Ajax
    ③ 事件函数
  • 多次异步调用的依赖分析
    ① 多次异步调用的结果顺序不确定
          $.ajax({
              url: 'http://localhost:3000/data',
              success: function(data) {
                  console.log(data);
              },
          });
          $.ajax({
              url: 'http://localhost:3000/data1',
              success: function(data) {
                  setTimeout(function() {
                      console.log(data);
                  }, 1000)
              },
          });
          $.ajax({
              url: 'http://localhost:3000/data2',
              success: function(data) {
                  console.log(data);
              },
          });

② 异步调用结果如果存在依赖需要嵌套

// 异步调用结果如果存在依赖需要嵌套
        $.ajax({
            url: 'http://localhost:3000/data',
            success: function(data) {
                console.log(data);
                $.ajax({
                    url: 'http://localhost:3000/data1',
                    success: function(data) {
                        console.log(data);
                        $.ajax({
                            url: 'http://localhost:3000/data2',
                            success: function(data) {
                                console.log(data);
                            },
                        });
                    },
                });
            },
        });

13.2 Promise 概述

Promise 是异步编程的一种解决方案,从语法上讲,promise是一个对象,从它可以获取异步操作的消息。

使用promise主要有一下好处:

  • 可以避免多层异步调用嵌套问题(回调地狱)
  • promise 对象提供了简洁的API,使得控制异步操作更加容易

Promise官网

13.3 Promise的基本使用

  • 实例化Promise对象,构造函数中传递函数,该函数中用于处理异步任务。
  • resolvereject两个参数用于处理成功和失败两种情况,并通过p.then获取处理结果
var p = new Promise(function(resolve, reject) {
  // 成功时调用 resolve()
  // 失败时调用 reject()
});
p.then(function(ret) {
  // 从resolve得到正常结果
},
function(ret) {
  // 从reject得到错误信息
});

举例为:

 var p = new Promise(function(resolve, reject) {
            // 这里用于实现异步任务
            setTimeout(function() {
                var flag = false;
                if (flag) {
                    // 正常情况
                    resolve('hello');
                } else {
                    // 异常情况
                    reject('出错了');
                };
            }, 100);
        });
        p.then(function(data) {
            console.log(data);
        }, function(info) {
            console.log(info);
        })

13.4 基于Promise处理Ajax请求

1. 处理原生Ajax

<script>
        // 基于Promise发送Ajax请求

        function queryData(url) {
            var p = new Promise(function(resolve, reject) {
                var xhr = new XMLHttpRequest();
                xhr.onreadystatechange = function() {
                    if (xhr.readyState != 4) return;
                    if (xhr.readyState == 4 && xhr.status == 200) {
                        // 处理正常的情况
                        resolve(xhr.responseText);
                    } else {
                        // 处理异常情况
                        reject('服务器错误');
                    };
                };
                xhr.open('get', url);
                xhr.send(null);
            });
            return p;
        }
        queryData('http://localhost:3000/data')
            .then(function(data) {
                console.log(data);
            }, function(info) {
                console.log(info);
            })
    </script>

2. 发送多次ajax请求

          queryData('http://localhost:3000/data')
            .then(function(data) {
                console.log(data);
                return queryData('http://localhost:3000/data1')
            })
            .then(function(data) {
                console.log(data);
                return queryData('http://localhost:3000/data2')
            })
            .then(function(data) {
                console.log(data);
            });

13.5 then参数中的函数返回值

1. 返回Promise 实例对象

  • 返回的该实例对象会调用下一个then
<body>
    <script>
        // 基于Promise发送Ajax请求

        function queryData(url) {
            return new Promise(function(resolve, reject) {
                var xhr = new XMLHttpRequest();
                xhr.onreadystatechange = function() {
                    if (xhr.readyState != 4) return;
                    if (xhr.readyState == 4 && xhr.status == 200) {
                        // 处理正常的情况
                        resolve(xhr.responseText);
                    } else {
                        // 处理异常情况
                        reject('服务器错误');
                    };
                };
                xhr.open('get', url);
                xhr.send(null);
            });
        };
        queryData('http://localhost:3000/data')
            .then(function(data) {
                return queryData('http://localhost:3000/data1');
            })
            .then(function(data) {
                return new Promise(function(resolve, reject) {
                    setTimeout(function() {
                        resolve(123);
                    }, 1000);
                });
            })
            .then(function(data) {
                console.log(data); // 123
            })
    </script>
</body>

2. 返回普通值

  • 返回的普通值会直接传递给下一个then,通过then参数中函数的参数接收该值。
<body>
    <script>
        // 基于Promise发送Ajax请求

        function queryData(url) {
            return new Promise(function(resolve, reject) {
                var xhr = new XMLHttpRequest();
                xhr.onreadystatechange = function() {
                    if (xhr.readyState != 4) return;
                    if (xhr.readyState == 4 && xhr.status == 200) {
                        // 处理正常的情况
                        resolve(xhr.responseText);
                    } else {
                        // 处理异常情况
                        reject('服务器错误');
                    };
                };
                xhr.open('get', url);
                xhr.send(null);
            });
        };
        queryData('http://localhost:3000/data')
            .then(function(data) {
                return queryData('http://localhost:3000/data1');
            })
            .then(function(data) {
                return new Promise(function(resolve, reject) {
                    setTimeout(function() {
                        resolve(123);
                    }, 1000);
                });
            })
            // .then(function(data) {
            //     console.log(data); // 123
            // })
            .then(function(data) {
                return 'hello'
            })
            .then(function(data) {
                console.log(data); // hello
            })
    </script>
</body>

13.6 Promise常用的API

1. 实例方法

  • p.then()得到异步任务的正确结果
  • p.catch()获取异常信息
  • p.finally() 成功与否都会执行(尚且不是正式标准)
<body>
    <script>
        // Promise常用API--实例方法

        function foo() {
            return new Promise(function(resolve, reject) {
                setTimeout(function() {
                    // resolve(123);
                    reject('error')
                }, 100);
            });
        };
        foo()
            // 得到异步任务的正确结果
            .then(function(data) {
                console.log(data);
            })
            // 获取异步信息
            .catch(function(data) {
                console.log(data);
            })
            // 成功与否都会执行
            .finally(function() {
                console.log('finished');
            })
    </script>
</body>

2. 对象方法

  • Promise.all() 并发处理多个异步任务,所有任务都执行完成才能得到结果
  • Promise.race() 并发处理多个异步任务,只要有一个任务完成就能得到结果
<body>
    <script>
        // Promise常用API-对象方法

        function queryData(url) {
            return new Promise(function(resolve, reject) {
                var xhr = new XMLHttpRequest();
                xhr.onreadystatechange = function() {
                    if (xhr.readyState != 4) return;
                    if (xhr.readyState == 4 && xhr.status == 200) {
                        // 处理正常的情况
                        resolve(xhr.responseText);
                    } else {
                        // 处理异常情况
                        reject('服务器错误');
                    };
                };
                xhr.open('get', url);
                xhr.send(null);
            });
        };
        var p1 = queryData('http://localhost:3000/a1');
        var p2 = queryData('http://localhost:3000/a2');
        var p3 = queryData('http://localhost:3000/a3');
        Promise.all([p1, p2, p3]).then(function(result) {
            console.log(result); // 返回三个值  ["Hello TOM", "Hello JERRY", "Hello SPIKE"]
        });
        Promise.race([p1, p2, p3]).then(function(result) {
            console.log(result); // Hello TOM
        });
    </script>
</body>

14. 接口调用-fetch用法

14.1 fetch 概述

1. 基本特性

  • 更加简单的数据获取方式、功能更强大、更灵活、可以看做是xhr的升级版
  • 基于Promise实现

2. 语法结构

fetch(url).then(fn2)
          .then(fn3)
          ...
          .catch(fn)

fetch官网

14.2 fetch 的基本使用

<body>
    <script>
        // Fetch API基本用法
        fetch('http://localhost:3000/fdata').then(function(data) {
             // text() 方法属于fetchAPI的一部分,他返回一个Promise实例对象,用于获取后台返回的数据
            return data.text();
        }).then(function(data) {
            // 注意这里得到的才是最终的数据
            console.log(data);
        })
    </script>
</body>

14.3 fetch请求参数

1. 常见配置选项

  • method(String): Http请求方式,默认为GET(GET、POST、PUT、DELETE)
  • body(String): HTTP的请求参数
  • headers(Object): HTTP的请求头,默认为{}

2. GET请求方式的参数传递

  • 传统的URL传递参数
        // 1. 传统的URL传递参数
        fetch('http://localhost:3000/books?id=123', {
                method: 'get'
            })
            .then(function(data) {
                // text() 方法属于fetchAPI的一部分,他返回一个Promise实例对象,用于获取后台返回的数据
                return data.text();
            }).then(function(data) {
                // 注意这里得到的才是最终的数据
                console.log(data);
            });
app.get('/books', (req, res) => {
    res.send('传统的URL传递参数!' + req.query.id);
});
  • Restful形式的URL传递参数
        // Restful形式的URL传递参数
        fetch('http://localhost:3000/books/456', {
                method: 'get'
            })
            .then(function(data) {
                // text() 方法属于fetchAPI的一部分,他返回一个Promise实例对象,用于获取后台返回的数据
                return data.text();
            }).then(function(data) {
                // 注意这里得到的才是最终的数据
                console.log(data);
            })
app.get('/books/:id', (req, res) => {
    res.send('Restful形式的URL传递参数!' + req.params.id);
});

运行结果

3. DELETE请求方式的参数传递

        // 2. DELETE请求方式的参数传递
        fetch('http://localhost:3000/books/789', {
                method: 'delete'
            })
            .then(function(data) {
                // text() 方法属于fetchAPI的一部分,他返回一个Promise实例对象,用于获取后台返回的数据
                return data.text();
            }).then(function(data) {
                // 注意这里得到的才是最终的数据
                console.log(data);
            });
app.delete('/books/:id', (req, res) => {
    res.send('DELETE请求方式传递参数!' + req.params.id);
});

运行结果

4. POST请求方式的参数传递

  • 传递方式的post传递参数
fetch('http://localhost:3000/books', {
                method: 'post',
                body: 'uname=lisi&pwd=123',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded'
                }
            })
            .then(function(data) {
                // text() 方法属于fetchAPI的一部分,他返回一个Promise实例对象,用于获取后台返回的数据
                return data.text();
            }).then(function(data) {
                // 注意这里得到的才是最终的数据
                console.log(data);
            });
  • json格式的post传递参数
        // 2> json格式的post传递参数
        fetch('http://localhost:3000/books', {
                method: 'post',
                body: JSON.stringify({
                    uname: '张三',
                    pwd: 456
                }),
                headers: {
                    'Content-Type': 'application/json'
                }
            })
            .then(function(data) {
                // text() 方法属于fetchAPI的一部分,他返回一个Promise实例对象,用于获取后台返回的数据
                return data.text();
            }).then(function(data) {
                // 注意这里得到的才是最终的数据
                console.log(data);
            });
app.post('/books', (req, res) => {
    res.send('POST请求方式传递参数!' + req.body.uname + '---' + req.body.pwd);
});

传统的post传递参数和json格式的post传递参数格式相同是由于app.use(bodyParser.json())这个中间件

运行结果

5. PUT请求方式传递参数

fetch('http://localhost:3000/books/123', {
                method: 'put',
                body: JSON.stringify({
                    uname: '张三',
                    pwd: 789
                }),
                headers: {
                    'Content-Type': 'application/json'
                }
            })
            .then(function(data) {
                // text() 方法属于fetchAPI的一部分,他返回一个Promise实例对象,用于获取后台返回的数据
                return data.text();
            }).then(function(data) {
                // 注意这里得到的才是最终的数据
                console.log(data);
            });
app.put('/books/:id', (req, res) => {
    res.send('PUT请求方式传递参数!' + req.params.id + '---' + req.body.uname + '---' + req.body.pwd);
});

运行结果

14.4 fetch响应结果

响应数据格式

  • text(): 将返回体处理成字符串类型
  • json(): 返回结果和JSON.parse(responseText)一样
<body>
    <script>
        // fetch响应结果的数据格式
        fetch('http://localhost:3000/json').then(function(data) {
            // return data.json();
            return data.text();
        }).then(function(data) {
            // console.log(data.uname);
            // console.log(data); // {"uname":"lisi","age":13,"gender":"male"} 类型为字符串
            var obj = JSON.parse(data);
            console.log(obj.uname, obj.age, obj.gender); // lisi 13 male
        })
    </script>
</body>
app.get('/json', (req, res) => {
    res.json({
        uname: 'lisi',
        age: 13,
        gender: 'male'
    })
});

15. 接口调用-axios用法

15.1 axios的基本特征

axios是一个基于Promise用于浏览器和node.js的HTTP客户端。
axios官网

它具有一下特征:

  • 支持浏览器和node.js
  • 支持Promise
  • 能拦截请求和响应
  • 自动转换JSON数据

15.2 axios的基本用法

<body>
    <script src="../../js/axios.map" type="text/babel"></script>
    <script src="../../js/axios.js"></script>
    <script>
        axios.get('http://localhost:3000/adata').then(function(ret) {
            // 注意data属性是固定的用法,用于获取后台的实际数据
            // console.log(ret.data);
            console.log(ret);
        })
    </script>
</body>

运行结果:

15.3 axios的常用API

  • get: 查询数据
  • post: 添加数据
  • put: 修改数据
  • delete: 删除数据

15.4 axios的参数传递

1. GET传递参数

  • 通过URL传递参数
        axios.get('http://localhost:3000/axios?id=123').then(function(ret) {
            console.log(ret.data);
        })
app.get('/axios', (req, res) => {
    res.send('axios get 传递参数' + req.query.id);
})

运行结果:

  • 通过Restful传递参数

axios参数传递.html

        // 2> 通过parmas选项传递参数
        axios.get('http://localhost:3000/axios/456').then(function(ret) {
            console.log(ret.data);
        });

index.js(后台接口)

app.get('/axios/:id', (req, res) => {
    res.send('axios get (Restful) 传递参数' + req.params.id);
});
  • 通过params选项传递参数

html文件

axios.get('http://localhost:3000/axios', {
            params: {
                id: 789
            }
        }).then(function(ret) {
            console.log(ret.data);
        });

后台接口

app.get('/axios', (req, res) => {
    res.send('axios get 传递参数' + req.query.id);
});

2. POST传递参数

  • 通过选项传递参数(默认传递的是json格式的数据)
axios.post('/adata', {
  uname: 'tom',
  pwd: 123
}).then(ret => {
  console.log(ret.data)
})
app.post('/axios', (req, res) => {
    res.send('axios post 传递参数' + req.body.uname + '---' + req.body.pwd);
});
  • 通过URLSearchParams传递参数(application/x-www-form-urlencoded)
var params = new URLSearchParams();
        params.append('uname', 'zhangsan');
        params.append('pwd', 111);
        axios.post('http://localhost:3000/axios', params).then(function(ret) {
            console.log(ret.data);
        });
app.post('/axios', (req, res) => {
    res.send('axios post 传递参数' + req.body.uname + '---' + req.body.pwd);
});

3. PUT传递参数

  • 通过选项传递参数(默认传递的是json格式的数据)
axios.put('http://localhost:3000/axios/123', {
            uname: 'lisi',
            pwd: 123
        }).then(function(ret) {
            console.log(ret.data);
        });
app.put('/axios/:id', (req, res) => {
    res.send('axios put 传递参数' + req.params.id + '---' + req.body.uname + '---' + req.body.pwd);
});
  • 通过URLSearchParams传递参数(application/x-www-form-urlencoded)
var params = new URLSearchParams();
params.append('uname', 'zhangsan');
params.append('pwd', 111);
axios.put('http://localhost:3000/axios/123', params).then(function(ret) {
 console.log(ret.data);
});
app.put('/axios', (req, res) => {
    res.send('axios put 传递参数' + req.body.uname + '---' + req.body.pwd);
});

4. DELETE传递参数

  • 通过URL传递参数
  • 通过Restful传递参数
  • 通过params选项传递参数
              axios.delete('http://localhost:3000/axios', {
                params: {
                    id: 111
                }
            })
            .then(ret => {
                console.log(ret.data);
            });
app.delete('/axios', (req, res) => {
    res.send('axios delete 传递参数' + req.query.id);
});

15.5 axios 的响应结果

响应结果的主要属性

  • data: 实际响应回来的数据
  • headers:响应头信息
  • status:响应状态码
  • statusText:响应状态信息

15.6 axios 的全局配置

  • axios.defaults.timeout = 3000; //超时时间
  • axios.defaults.baseURL = 'http:localhost:3000/app'; //默认地址
  • axios.defaults.headers['mytoken'] = 'aqwerwqwerqwer2ewrwe23eresf23'; // 设置请求头 值为自定义的
 <script>
        // axios的全局配置

        // 配置请求的基准URL地址
        axios.defaults.baseURL = 'http://localhost:3000';
        // 配置请求头信息
        axios.defaults.headers['mytoken'] = 'hello';
        axios.get('axios-json').then(function(ret) {
            console.log(ret.data.uname);
        });
    </script>

15.6 axios拦截器

1. 请求拦截器

在请求发出之前设置一些信息

2. 响应拦截器

在获取数据之前对数据做一些加工处理

       <script>
        // axios拦截器

        // 1. 请求拦截器

        // 添加一个请求拦截器
        axios.interceptors.request.use(function(config) {
            console.log(config.url);
            config.headers.mytoken = 'nihao';
            // 在请求发出之前进行一些信息设置
            return config;
        }, function(err) {
            // 处理响应的错误信息
            console.log(err);
        });

        // 2. 响应拦截器

        // 添加一个响应拦截器
        axios.interceptors.response.use(function(res) {
            // console.log(res);
            var data = res.data;
            // 在这里对返回的数据进行处理
            return data;
        }, function(err) {
            // 处理响应的错误信息
            console.log(err);
        });

        axios.get('http://localhost:3000/adata').then(function(data) {
            console.log(data);
        });
    </script>

16. 接口调用-async/await用法

16.1 async/await的基本用法

  • async/await是ES7引入的新的语法,可以更加方便的进行异步操作
  • async 关键字用于函数上(async函数的返回值是Promise实例对象)
  • await 关键字用于async 函数当中(await可以得到异步的结果)
        // async function queryData() {
        //     var ret = await axios.get('adata');
        //     // console.log(ret.data);
        //     return ret.data
        // };

        async function queryData() {
            var ret = await new Promise(function(resolve, reject) {
                    setTimeout(function() {
                        resolve('nihao');
                    })
                })
                // console.log(ret.data);
            return ret;
        };

        queryData().then(function(data) {
            console.log(data);
        });

16.2 async/await 处理多个异步请求

多个异步请求的场景

          async function queryData() {
            var ret = await new Promise(function(resolve, reject) {
                    setTimeout(function() {
                        resolve('nihao');
                    })
                })
                // console.log(ret.data);
            return ret;
        };

        queryData().then(function(data) {
            console.log(data);
        });

17. Vue全家桶-前端路由

原文地址:https://www.cnblogs.com/counter/p/14753361.html