学习 vue2.X 这篇文章就够了

1、vue指令以及案例

1.1 学习目标
  • 能够说出 vue 的基本用法
  • 能够说出 vue 的模板语法
  • 能够说出 vue 的常用特性
  • 能够基于 vue 实现案例效果
1.2 vue 概述

尤雨溪

vue:渐进式 JavaScript 框架

声明式渲染 => 组件系统 => 客户端路由 => 集中式状态管理 => 项目构建

https://cn.vuejs.org/v2/api/

  • 易用:熟悉HTML css JavaScript知识后,可快速上手vue
  • 灵活:在一个库和一套完整框架之间自如伸缩
  • 高校:20KB运行大小,超快虚拟DOM
1.3 vue 之 hello world
<body>
    <div id="app">
        <!-- {{}} 插值表达式,里面写变量名字 -->
        <!-- {{}} 插值表达式,里面写变量名字 -->
        <div>{{msg}}</div>
        <div>{{1+2}}</div>
        <!-- 3 -->
        <div>{{msg+'---'+123}}</div>
        <!-- Hello world---123 -->
    </div>
    <script src="./js/vue.js"></script>
    <script>
        /* 
        vue的使用步骤
        1、需要提供标签用于填充数据
        2、引入 vue.js 库文件
        3、使用vue的语法做功能
        4、把 vue 提供的数据,填充到标签里面

         */
        var vm = new Vue({
            // 创建一个vue实例
            // el 表示 那个容器,里面写的是选择器
            // data 填充数据
            el: '#app',
            data: {
                msg: 'Hello world'
            }
        })
    </script>
</body>
  • el:元素的挂载位置(值可以是CSS选择器或者DOM元素)
  • data:模型数据(值是一个对象)

插值表达式

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

vue代码运行原理分析

  • 概述编译过程的概念(vue语法 = > 原生语法)
  • vue代码 经过 vue 框架处理,转变成原生js代码
1.4 模板语法概述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XYsdaJps-1620387784164)(vue基础.assets/image-20201018122455568.png)]

前端渲染方式

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

vue 模块语法

  • 插值表达式
  • 指令
  • 事件绑定
  • 属性绑定
  • 样式绑定
  • 分支循环结构
1.5 v-cloak 指令

什么是指令:指令的本质就是自定义属性

v-cloak指令用法

  • 插值表达式存在的问题:“ 闪动 ”
  • 如何解决此问题:使用 v-cloak 指令
  • 解决此问题的原理:先隐藏,替换好值之后再显示最终的值
<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        [v-cloak] {
            display: none;
        }
    </style>
</head>

<body>
    <div id="app">
        <!-- {{}} 插值表达式,里面写变量名字 -->
        <div v-cloak>{{msg}}</div>
        <div v-cloak>{{1+2}}</div>
        <!-- 3 -->
        <div v-cloak>{{msg+'---'+123}}</div>
        <!-- Hello world---123 -->
    </div>
    <script src="./js/vue.js"></script>
    <script>
        /* 
        v-cloak 指令的用法
        1、提供样式
            [v-cloak]{
                display:none;
            }
        2、在插值表达式所在的标签中,添加 v-cloak指令
        原理:先通过样式隐藏内容,然后在内存中进行值的替换,替换好之后在显示最终的结果
         */
        var vm = new Vue({
            el: '#app',
            data: {
                msg: 'Hello world'
            }
        })
    </script>
</body>

</html>
1.6 v-text v-html v-pre 数据填充的三个指令

1、v-text 填充纯文本

​ 相比插值表达式更加简洁

2、v-html 填充HTML片段

​ 存在安全问题

​ 本网站内部数据可以使用,来自第三方的数据不可以用

3、v-pre 填充原始信息

​ 显示原始信息,跳过编译过程(分析编译过程)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zGfCHDSy-1620387784166)(vue基础.assets/image-20201018125344603.png)]

<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        [v-cloak] {
            display: none;
        }
    </style>
</head>

<body>
    <div id="app">
        <div>{{msg}}</div>
        <div v-text="msg"></div>
        <!-- v-text 没有闪动问题,显示结果也是 Hello world  -->
        <div v-html="msg1"></div>
        <!-- 显示的 h1 标签 -->
        <div v-pre>{{msg}}</div>
        <!-- 显示结果是 {{msg}} -->
    </div>
    <script src="./js/vue.js"></script>
    <script>

        var vm = new Vue({
            el: '#app',
            data: {
                msg: 'Hello world',
                msg1: '<h1>你好</h1>'
            }
        })
    </script>
</body>

</html>
1.7 数据响应式概念 与 v-once 用法

如何理解响应式

  1. html5中的响应式(屏幕尺寸的变化导致样式的变化)
  2. 数据的响应式(数据的变化导致页面内容的变化),数据驱动页面内容的变化。

数据绑定:将数据填充到标签中

v-once:只显示一次,显示内容之后不再具有响应式功能

<div v-once>{{msg}}</div>
<!-- 只会显示一次,你在页面的控制台修改了值,他也不会变
	v-once的应用场景:如果显示的信息后续不需要再修改,可以使用 		v-once ,这样可以提高性能
-->
1.8 双向数据绑定与v-model 的用法

v-model 指令在表单 元素上

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VXeUMw4E-1620387784168)(vue基础.assets/image-20201018131417691.png)]

双向:

    1、用户修改页面内容,数据会变
    2、数据发生变化,插值表达式也会跟着发生变化
<body>
    <div id="app">
        <div>{{msg}}</div>
        <div>
            <input type="text" v-model="msg">
        </div>
    </div>
    <script src="./js/vue.js"></script>
    <script>

        var vm = new Vue({
            el: '#app',
            data: {
                msg: 'Hello world',
                msg1: '<h1>你好</h1>'
            }
        })
    </script>
</body>
1.9 MVVM 设计思想分析
  • M(model):模型,就是data的数据
  • V(view):DOM 元素
  • VM(View-Model):实现控制逻辑

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YUE1wTtK-1620387784172)(vue基础.assets/image-20201018132213553.png)]

1.10 事件绑定

v-on 指令用法

<input type="button" v-on:click='num++'>

v-on 简写形式

<input type="button" @click='num++'>

在Vue中,方法定义在 vue的实例对象中,和data同一级,值是一个对象

事件函数的调用方式:

<button v-on:click='handle'>点击</button>
<button @click='handle()'>点击2</button>
<body>
    <div id="app">
        <div>{{num}}</div>
        <div>
            <button v-on:click='num++'>点击</button>
            <button @click='num++'>点击2</button>
        </div>
        <div>
            <button v-on:click='handle'>点击</button>
            <button @click='handle()'>点击2</button>
        </div>
    </div>
    <script src="./js/vue.js"></script>
    <script>

        var vm = new Vue({
            el: '#app',
            data: {
                num: 0,
            },
            methods: {
                handle: function () {
                    // 注意:这里不能直接写 num++
                    // this 就是 vue的实例vm
                    console.log(this);
                    this.num++;
                }
            }
        })
    </script>
</body>
1.11 事件函数参数传递方式
<body>
    <div id="app">
        <div>{{num}}</div>
        <div>
            <button v-on:click='handle1'>点击</button>
            <!-- 
                如果事件直接绑定函数名称,那么默认会携带 事件对象  作为事件函数的第一个参数
             -->
            <button @click='handle(123,456,$event)'>点击2</button>
            <!-- 
                如果事件绑定函数调用,那么事件对象必须作为最后一个参数,进行传递,并且名字为 $event
             -->

        </div>
    </div>
    <script src="./js/vue.js"></script>
    <script>

        var vm = new Vue({
            el: '#app',
            data: {
                num: 0,
            },
            methods: {
                handle: function (p, p1, event) {
                    // 注意:这里不能直接写 num++
                    // this 就是 vue的实例vm
                    //console.log(this);
                    console.log(event.target);
                    this.num++;
                },
                handle1: function (event) {
                    console.log(event.target);
                }
            }
        })
    </script>
</body>
1.12 事件修饰符的用法
        <a href="" @click.stop="handle">跳转</a>
        <a href="" @click.prevent="handle">跳转</a>
				<a href="" @click.prevent.stop="handle">跳转</a>
				
				<!--只执行直接绑定在此元素上的事件,冒泡不会执行找个元素的事件 -->
				<a href="" @click.self="handle">跳转</a>
<div style="width: 100px;height: 100px;background: #000;" @click.self='handle'>
	<a href="" @click='handle'>跳转</a>
</div>
<!-- 
	如果不给父元素加 .self 则点击 a 的时候,会触发 父元素的点击事件,若给父元素加上 .self 则只会在用户点击父元素的时候触发,不会因为冒泡触发
-->
<body>
    <div id="app">
        <div style="width: 100px;height: 100px;background: #000;" @click='handle'>
            <a href="" @click.stop='handle'>跳转</a>
        </div>
        <a href="" @click.stop="handle">跳转</a>
        <a href="" @click.prevent="handle">跳转</a>
    </div>
    <script src="./js/vue.js"></script>
    <script>

        var vm = new Vue({
            el: '#app',
            data: {
                num: 0,
            },
            methods: {
                handle: function (p, p1, event) {
                    alert('11')
                },
            }
        })
    </script>
</body>
1.13 按键修饰符的用法
    <!-- 
        案件修饰符
        1、 .enter 回车键
        <input v-on:keyup.enter='submit'>
        2、 .delete  删除键
        <input v-on:keyup.delete='submit'>
     -->
1.14 自定义按键修饰符
<input type="text" @keyup.65='handle'>
<!--这样表示  当按了键盘的小写a或者大写A 的时候 触发的事件-->
<input type="text" @keyup.s='handle'>
<!--这样表示  当按了键盘的小写s或者大写S 的时候 触发的事件-->

<!--自定义按键修饰符-->
<input type="text" v-model="msg" @keyup.aaa="handle">
Vue.config.keyCodes.aaa = 65
// 这个后面的值,代表按键的ASII码,前面的值就是一个名字
// 这样表示只有按 a(65 对应的就是a) 的时候,并且绑定 @keyup.aaa 事件才会触发后面的函数
<!--名字是自定义的,但是对应的值必须是按键对应的ASII码 -->
1.15 简单计算器案例
<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        [v-cloak] {
            display: none;
        }
    </style>
</head>

<body>
    <div id="app">
        <div>
            数值A:<input type="text" v-model="num1">
        </div>
        <div>
            数值A:<input type="text" v-model="num2">
        </div>
        <div>
            <button @click="handle">计算</button>
        </div>
        <div>
            计算结果<span>{{sum}}</span>
        </div>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                num1: '',
                num2: '',
                sum: '',
            },
            methods: {
                handle: function () {
                    this.sum = parseInt(this.num1) + parseInt(this.num2)

                },
            }
        })
    </script>
</body>

</html>
1.16 属性绑定基本用法

不能直接在后面写地址

<body>
    <!-- 
        属性绑定
        <a v-bind:href='url'>跳转</a>
        缩写形式
        <a :href='url'>跳转</a>
     -->
    <div id="app">
        <a v-bind:href='url'>跳转</a>
        <button v-on:click='handle'>切换</button>
    </div>
    <script src="./js/vue.js"></script>
    <script>

        var vm = new Vue({
            el: '#app',
            data: {
                url: 'http://www.baidu.com'

            },
            methods: {
                handle: function () {
                    // 修改url
                    this.url = 'http://itcast.cn'
                }
            }
        })
    </script>
</body>
1.17 v-model 底层原理分析
<body>
    <div id="app">
        <div>{{msg}}</div>
        <div>
            <input type="text" @input="handle" v-bind:value="msg">
        </div>
    </div>
    <script src=" ./js/vue.js"></script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                msg: ''
            },
            methods: {
                handle: function (e) {
                    this.msg = e.target.value
                }
            }
        })
    </script>
</body>
1.18 class绑定对象用法
<div :class="{active:isActive}"></div>
<!-- 
键值对的形式,左边是类名,右边是控制类的属性
需要在data 里面写一个 标志变量,控制它 true显示类,false不显示
-->
    <style>
        .active {
            border: 1px solid red;
            width: 100px;
            height: 100px;
        }

        .error {
            background: orange;
        }
    </style>
</head>

<body>
    <div id="app">
        <div class="one" :class="{active:isActive,error:isError}"></div>
        <!-- 键值对 左边是类名,右边控制整个类 -->
        <!-- 不会覆盖原先的类 -->
        <button @click="handle">切换</button>
    </div>
    <script src=" ./js/vue.js"></script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                isActive: true,
                isError: true
            },
            methods: {
                handle: function () {
                    this.isActive = !this.isActive
                }
            }
        })
    </script>
</body>
1.19 class绑定数组用法
<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .active {
            border: 1px solid red;
            width: 100px;
            height: 100px;
        }

        .error {
            background: orange;
        }
    </style>
</head>

<body>
    <div id="app">
        <div class="one" :class="[activeClass,errorClass]"></div>
        <!-- 数组内写的都是变量 -->
        <button @click="handle">切换</button>
    </div>
    <script src=" ./js/vue.js"></script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                activeClass: 'active',
                // 左边是变量,右边是类名
                errorClass: 'error'
            },
            methods: {
                handle: function () {
                    this.isActive = !this.isActive
                }
            }
        })
    </script>
</body>

</html>
1.20 class绑定3个细节
  • 对象绑定和数组绑定可以结合使用
  • 默认的class 不会被 :class 覆盖掉
  • 如果在data里面写 class的数组形式,则可以直接在里面写 [‘类名’,‘类名’]
  • 如果在 data 里面写 class的对象形式,则可以直接在里面写{类名: true或者false}
<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .active {
            border: 1px solid red;
            width: 100px;
            height: 100px;
        }

        .error {
            background: orange;
        }
    </style>
</head>

<body>
    <div id="app">
        <div class="one" :class="[activeClass,{error:isError}]"></div>
        <!-- 数组内写的都是变量 -->
        <button @click="handle">切换</button>
        <div :class="arrClasses"></div>
        <div :class="objClasses"></div>
    </div>
    <script src=" ./js/vue.js"></script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                activeClass: 'active',
                // 左边是变量,右边是类名
                isError: true,
                arrClasses: ['active'],
                objClasses: {
                    active: true,
                    error: true
                }
            },
            methods: {
                handle: function () {
                    this.isActive = !this.isActive
                }
            }
        })
    </script>
</body>

</html>
1.21 style绑定用法

和 class 类似

<!--对象语法 -->
<div :style="{color:activeColor}"></div>
<!--数组语法 --->
<div :style="[baseStyles]"></div>
<body>
    <div id="app">
        <div :style="{color:isColor}">2222</div>
        <div :style="objStyle">2222</div>
        <div>数组类型控制style</div>
        <div :style="[objStyle,overrideStyles]"></div>
    </div>
    <script src=" ./js/vue.js"></script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                isColor: 'red',
                objStyle: {
                    border: '1px solid green',
                    width: '200px',
                    height: '200px'
                },
                overrideStyles: {
                    border: '5px solid orange',
                    backgroundColor: 'blue'
                }
            },
            methods: {

            }
        })
    </script>
</body>
1.22 分支结构用法
  • v-if
  • v-else
  • v-else-if 判断多个的时候
  • v-show

前三个指令渲染出来,只会有一个div

  • v-if 控制元素是否渲染到页面
  • v-show 控制元素是否显示(已经渲染到了页面)
<body>
    <div id="app">
        <div v-if="score>=90">优秀</div>
        <div v-else-if="score>=80">良好</div>
        <div v-else-if="score>=60">一般</div>
        <div v-else>比较差的</div>
        <div v-show="flag">测试v-show</div>
        <!-- v-show 会渲染到DOM身上,但是不会显示,因为设置了 display none -->
    </div>
    <script src="./js/vue.js"></script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                score: 99,
                flag: false,
            }
        })
    </script>
</body>
1.23 循环结构遍历数组于key的作用分析
<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">
        <ul>
            <!-- in 是关键字,右边是遍历谁,左边是每一项 -->
            <li v-for='item in fruits'>{{item}}</li>
            <!-- 
                apple
                orange
                banana

             -->
            <li v-for='(item,index) in fruits'>{{item}}+'---'+{{index}}</li>
             <!-- 
                apple+'---'+0
                orange+'---'+1
                banana+'---'+2
              -->
        </ul>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                fruits: ['apple', 'orange', 'banana']
            }
        })
    </script>
</body>
1.24 遍历对象
<body>
    <div id="app">
        <ul>
            <li :key="index" v-for="(value,key,index) in obj">{{value}}+'--'{{key}}+'--'{{index}}</li>
            <!-- 
                value: 是值
                key:是名称
                index :是索引
             -->
        </ul>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                obj: {
                    uname: '呆呆狗',
                    age: 20,
                    gender: '前端开发工程师'
                }
            }
        })
    </script>
</body>
1.25
1.26
1.27
1.28 选项卡
<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style type="text/css">
        .tab ul {
            overflow: hidden;
            padding: 0;
            margin: 0;
        }

        .tab ul li {
            box-sizing: border-box;
            padding: 0;
            float: left;
            width: 100px;
            height: 45px;
            line-height: 45px;
            list-style: none;
            text-align: center;
            border-top: 1px solid blue;
            border-right: 1px solid blue;
            cursor
        }

        .tab ul li:nth-child(1) {
            border-left: 1px solid blue;
        }

        .tab ul li.active {
            background-color: orange;
        }

        .tab div {
            width: 500px;
            height: 300px;
            display: none;
            text-align: center;
            font-size: 30px;
            line-height: 300px;
            border: 1px solid blue;
            border-top: 0px;
        }

        .tab div.current {
            display: block;
        }
    </style>
</head>

<body>
    <div id="app">
        <div class="tab">
            <ul>
                <li v-for='(item,index) in list' @click="handle(index)" :class="hoverIndex==index?'active':''">
                    {{item.title}}</li>
            </ul>
            <div v-for='(item, index) in list' :class="hoverIndex==index?'current':''">
                <img :src="item.path">
            </div>
        </div>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                hoverIndex: 0,
                list: [
                    {
                        id: 1,
                        title: 'apple',
                        path: 'img/apple.png'
                    },
                    {
                        id: 2,
                        title: 'orange',
                        path: 'img/orange.png'
                    },
                    {
                        id: 3,
                        title: 'lemon',
                        path: 'img/lemon.png'
                    }]
            },
            methods: {
                handle: function (index) {
                    this.hoverIndex = index
                    console.log(this.hoverIndex);
                }
            }
        })
    </script>
</body>

</html>
1.29 常用特性概述与表单效果
  • 表单操作
  • 自定义指令
  • 计算属性
  • 过滤器
  • 侦听器
  • 生命周期

表单操作

基于vue 的表单操作:input 单行文本、textarea 多行文本 、select 下拉多选 、 radio 单选框 、 checkbox 多选框

1.30 表单 input radio checkbox
<input type="text" v-model="uname">
            <div>
                <span>性别:</span>
                <span>
                    <input type="radio" id="male" value="1" name="xm" v-model="gender">
                    <label for="male"></label>
                    <input type="radio" id="female" value="2" name="xm" v-model="gender">
                    <label for="female" id="female"></label>

                </span>
                <!-- 要是 radio 类型,必须要设置name,并且name相同 -->
                <!-- 
                    vue 单选的做法是
                    1、给这两个input 设置 value 和 v-model 
                    2、第一个 input value为,第二个为2
                    3、两个input 的v-model 的值必须相同
                    4、若在data 中 给v-model 变量设置的值等于谁,谁就是默认选择
                -->
            </div>
            <div>
                <span>爱好:</span>
                <input type="checkbox" id="ball" value="1" v-model="habit">
                <label for="ball">篮球</label>
                <input type="checkbox" id="sing" value="2" v-model="habit">
                <label for="sing">唱歌</label>
                <input type="checkbox" id="code" value="3" v-model="habit">
                <label for="code">写代码</label>
            </div>
            <!-- 
                处理多项选择,data中的值必须是数组,也是根据值找与value相同的值
             -->
    <script>
        var vm = new Vue({
            el: ' #app',
            data: {
                uname: "呆呆狗",
                gender: 1,// 若是1 则会找绑定v-model gender的输入框,找到value等于1的,2则找到2
                habit: [1, 2],

            },
            methods: {
                handle: function () {
                    console.log(this.uname);
                    console.log(this.gender);
                    console.log(this.habit.join(''));// 12
                }

            }
        })

    </script>
1.31 表单基本操作 select textarea
                <select v-model="selectAnser">
                    <!-- multiple 表示多选 -->
                    <option value="0">请选择职业...</option>
                    <option value="1">教师</option>
                    <option value="2">软件工程师</option>
                    <option value="3">律师</option>
                </select>
            <div>
                <span>个人简介:</span>
                <textarea v-model="textMore"></textarea>
            </div>
    <script>
        var vm = new Vue({
            el: ' #app',
            data: {
                uname: "呆呆狗",
                gender: 1,// 若是1 则会找绑定v-model gender的输入框,找到value等于1的,2则找到2
                habit: [1, 2],
                selectAnser: 2, // 单选是一个数,多选是数组
                textMore: '请输入内容'
            },
            methods: {
                handle: function () {
                    console.log(this.uname);
                    console.log(this.gender);
                    console.log(this.habit.join(''));// 12
                }

            }
        })

    </script>
1.32 表单域修饰符用法
  • number 转化为数值
  • trim 去掉开始和结尾的空格 中间的问题是去不掉的
  • lazy 将input 事件切换为 change事件
<input v-model.trim="msg"></input>

v-model 默认是捆绑着 input事件的

1.33 自定义指令用法
    <div id="app">
        <input type="text" v-focus>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        // 第一个参数是指令的名称,自定义的
        Vue.directive('focus', {
            inserted: function (el) {
                // 第一个参数就是元素,就是指令所绑定的元素
                // 获取元素的焦点
                el.focus()
            }
        })
        var vm = new Vue({
            el: ' #app',
            data: {
            },
            methods: {

            }
        })

    </script>
1.34 自定义指令(带参数)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ffhaVaGo-1620387784174)(vue基础.assets/image-20201019163344281.png)]

    <div id="app">
        <input type="text" v-color="msg">
    </div>
    <script src="./js/vue.js"></script>
    <script>
        // 第一个参数是指令的名称,自定义的
        Vue.directive('color', {
            inserted: function (el, binding) {
                // 第一个参数就是元素,就是指令所绑定的元素
                el.style.backgroundColor = binding.value
            }
        })
        var vm = new Vue({
            el: ' #app',
            data: {
                msg: 'red'
            },
            methods: {

            }
        })

    </script>
1.35 自定义局部指令
    <div id="app">
        <input type="text" v-color="msg">
    </div>
    <script src="./js/vue.js"></script>
    <script>
        var vm = new Vue({
            el: ' #app',
            data: {
                msg: 'red'
            },
            methods: {

            },
            directives: {
                color: {
                    inserted: function (el, binding) {
                        // 第一个参数就是元素,就是指令所绑定的元素
                        el.style.backgroundColor = binding.value
                    }
                }
            }
        })

    </script>
1.36 计算属性基本用法

把复杂的表达式抽取出来,使模板内容更加简洁

  • 必须要有 return
  • 必须写在组件中
  • 是基于 data 的值进行变化的
    <div id="app">
        <div>{{msg}}</div>
        <div>{{reverseString}}</div>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        var vm = new Vue({
            el: ' #app',
            data: {
                msg: 'red'
            },
            methods: {

            },
            computed: {
              // 第一个参数是自定义的名字
                reverseString: function () {
                    return this.msg.split("").reverse().join("")
                }
            }
        })

    </script>
1.37 计算属性与方法的区别
  • 计算属性是基于他们的依赖进行缓存的
  • 方法不存在缓存
    <div id="app">
        <div>{{msg}}</div>
        <div>{{reverseString}}</div>
        <div>{{reverseString}}</div>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        var vm = new Vue({
            el: ' #app',
            data: {
                msg: 'red'
            },
            methods: {

            },
            computed: {
              // 第一个参数是自定义的名字
                reverseString: function () {
                  console.log('执行了')
                    return this.msg.split("").reverse().join("")
                }
            }
        })

    </script>

上面的代码,只会输出一次 ‘执行了’,因为执行完以后,缓存中有,所以不会再执行那个函数。计算属性的值,没有发生变化的时候,是先访问缓存的值

1.38 侦听器的基本用法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3njUR25M-1620387784176)(vue基础.assets/image-20201019170218502.png)]

应用场景:数据变化时执行异步或开销较大的操作

    <div id="app">
        <div>
            <span>名:</span>
            <span>
                <input type="text" v-model="firstName">
            </span>
        </div>
        <div>
            <span>姓:</span>
            <span>
                <input type="text" v-model="lastName">
            </span>
        </div>
        <div>{{fullName}}</div>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        var vm = new Vue({
            el: ' #app',
            data: {
                firstName: "Jim",
                lastName: "Green",
                fullName: "Jim Green"
            },
            methods: {

            },
            watch: {
                firstName: function (val) {
                    // fullName 要和变量名字一致
                    // val表示 firstName 最新值
                    this.fullName = val + '  ' + this.lastName
                },
                lastName: function (val) {
                    this.fullName = this.firstName + '  ' + val
                }
            }
        })

    </script>
1.39 侦听器案例

<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <div>
            <span>用户名:</span>
            <span>
                <input type="text" v-model.lazy='uname'>
            </span>
            <span>
                {{tip}}
            </span>
        </div>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        /* 
            1、采用侦听器监听用户名的变化
            2、如果变化,调用后台接口进行验证
            3、根据验证的结果调整提示信息
        */
        var vm = new Vue({
            el: '#app',
            data: {
                uname: '',
                tip: '',

            },
            methods: {
                checkname: function (uname) {
                    // 调用接口,但是可以使用定时任务的方式模拟接口调用
                    // 定时器中的this指向的是window
                    var that = this;
                    setTimeout(function () {
                        // 模拟接口调用
                        if (uname == 'admin') {
                            that.tip = '用户名已经存在,请更换用户名'
                        }
                        else {
                            that.tip = '用户名可以使用'
                        }
                    }, 2000)
                }
            },
            watch: {

                uname: function (val) {
                    // 调用后台接口进行验证用户名的合法性
                    this.checkname(val);
                    // 修改提示信息
                    this.tip = '正在验证'
                }
            }
        })
    </script>
</body>

</html>
1.40 过滤器基本用法

格式化数据,比如将字符串格式首字母大写、日期格式化等

一个插值表达式,一个属性绑定

<div>{{msg | 过滤器名称}}</div>
<div v-bind:id="id | 过滤器名称"></div>
Vue.filter('过滤器名称',function(value){
  // 过滤器业务逻辑
})

//也可以局部定义
    <div id="app">
        <input type="text" v-model="msg">
        <div>{{msg|upper}}</div>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        Vue.filter('upper', function (val) {
            // 获取到的值
            return val.charAt(0).toUpperCase() + val.slice(1)
        })
        var vm = new Vue({
            el: ' #app',
            data: {
                msg: ''
            },
            filters: {
                upper: function (val) {
                    // 名称,
                    return val.charAt(0).toUpperCase() + val.slice(1)
                }
            }

        })

    </script>
1.41 带参数的过滤器
        Vue.filter('过滤器名称',function(val,arg1,arg2){
            // val 必须是第一个,他表示传递过来的要处理的参数
            // arg 是其他的参数
        })
    <div id="app">
        <div>{{date | format('yyyy-MM-dd')}}</div>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        Vue.filter('format', function (val, arg) {
            // 这里的arg 指的就是 'yyyy-MM-dd'
            if (arg == 'yyyy-MM-dd') {
                var ret = ''
                ret += val.getFullYear() + '-' + (val.getMonth() + 1) + '-' + val.getDate()
                return ret
            }
        })
        var vm = new Vue({
            el: ' #app',
            data: {
                date: new Date()
            },
            filters: {

            }

        })

    </script>
1.42 vue实例的声明周期

创造前后 => 安装前后 =>更新前后 =>销毁前后

挂载包括:创造和安装

  • 挂载(初始化相关属性)
    1. beforeCreate
    2. created
    3. beforeMount
    4. mounted
  • 更新(元素或组件的变更操作)
    1. beforeUpdate
    2. updated
  • 销毁(销毁相关属性)
    1. beforeDestroy
    2. destroyed

vue实例的产生过程

  1. beforeCreate 在实例初始化之后,数据观测和时间配置之前被调用
  2. created 在实例创建完成后被立即调用
  3. beforeMount 在挂载开始之前被调用
  4. mounted el被新创建的 vm.$el 替换 。并挂载到实例上去之后调用该钩子
  5. beforeUpdate 数据更新时调用,发生在虚拟DOM打补丁之前
  6. updated 由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子
  7. beforeDestr0y 实例销毁之前调用
  8. destroyed 实例销毁后调用
<body>
    <div id="app">
        <div>{{msg}}</div>
        <button @click='update'>更新</button>
        <button @click='destroy'>销毁</button>
    </div>
    <script src="./js/vue.js"></script>
    <script type="text/javascript">
        /*
          Vue实例的生命周期
          
        */
        var vm = new Vue({
            el: '#app',
            data: {
                msg: '生命周期'
            },
            methods: {
                update: function () {
                    this.msg = 'hello world';
                },
                destroy: function () {
                    this.$destroy();
                }
            },
            // 挂载阶段  初始化相关属性,例如 watch ,methods
            beforeCreate: function () {
                console.log('beforeCreate');
            },
            created: function () {
                console.log('created');
            },
            beforeMount: function () {
                console.log('beforeMount');
            },
            mounted: function () {
                // 这个函数 执行 就表示初始化已经完成
                // 最常用的就是,调用后台接口,
                console.log('mounted');
            },

            // 更新阶段 元素或组件的变更操作
            beforeUpdate: function () {
                console.log('beforeUpdate');
            },
            updated: function () {
                console.log('updated');
            },

            // 销毁阶段 销毁相关属性
            beforeDestroy: function () {
                console.log('beforeDestroy');
            },
            destroyed: function () {
                console.log('destroyed');
            }
        });
    </script>
</body>

2、图书馆综合案例

2.1 关于数组响应式的问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ltLunJrQ-1620387784177)(file://F:/web%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/%E9%BB%91%E9%A9%AC%E8%87%AA%E5%AD%A6/vue/B%E7%AB%99/B%E7%AB%99vue%E7%AC%94%E8%AE%B0.assets/image-20200801140707017.png?lastModify=1603112008)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TmlOXKXI-1620387784178)(vue基础.assets/image-20200801141548596.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R56otYHh-1620387784179)(vue基础.assets/image-20200801142355344.png)]

在VUE中用索引修改的数据不是响应式变化 的,上面的两个方法,可以用在数组和对象身上

2.2 图书案例源码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style type="text/css">
        .grid {
            margin: auto;
            width: 530px;
            text-align: center;
        }

        .grid table {
            border-top: 1px solid #C2D89A;
            width: 100%;
            border-collapse: collapse;
        }

        .grid th,
        td {
            padding: 10;
            border: 1px dashed #F3DCAB;
            height: 35px;
            line-height: 35px;
        }

        .grid th {
            background-color: #F3DCAB;
        }

        .grid .book {
            padding-bottom: 10px;
            padding-top: 5px;
            background-color: #F3DCAB;
        }

        .total {
            height: 30px;
            line-height: 30px;
            background-color: orangered;
        }
    </style>
</head>

<body>
    <div id="app">
        <div class="grid">
            <div>
                <h1>图书管理</h1>
                <div class="book">
                    <div>
                        <label for="id">
                            编号:
                        </label>
                        <input type="text" id="id" v-model='id' :disabled="flag" v-focus>
                        <label for="name">
                            名称:
                        </label>
                        <input type="text" id="name" v-model='name'>
                        <button @click='handle' :disabled='submitFlag'>提交</button>
                    </div>
                </div>
            </div>
            <div class="total">
                <span>图书总数:</span>
                <span>{{total}}</span>
            </div>
            <table>
                <thead>
                    <tr>
                        <th>编号</th>
                        <th>名称</th>
                        <th>时间</th>
                        <th>操作</th>
                    </tr>
                </thead>
                <tbody>
                    <tr :key='item.id' v-for='item in books'>
                        <td>{{item.id}}</td>
                        <td>{{item.name}}</td>
                        <td>{{item.date | format('yyyy-MM-dd hh:mm:ss')}}</td>
                        <td>
                            <a href="" @click.prevent='toEdit(item.id)'>修改</a>
                            <span>|</span>
                            <a href="" @click.prevent='deleteBook(item.id)'>删除</a>
                        </td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>
    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript">
        Vue.directive('focus', {
            inserted: function (el) {
                el.focus();
            }
        })
        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: {
                submitFlag: false,
                flag: false,
                id: '',
                name: '',
                books: [{
                    id: 1,
                    name: '三国演义',
                    date: 2525609975000
                }, {
                    id: 2,
                    name: '水浒传',
                    date: 2525609975000
                }, {
                    id: 3,
                    name: '红楼梦',
                    date: 2525609975000
                }, {
                    id: 4,
                    name: '西游记',
                    date: 2525609975000
                }]
            },
            methods: {
                handle: function () {
                    if (this.flag) {
                        // 编辑图书
                        // 就是根据当前的ID去更新数组中对应的数据
                        this.books.some((item) => {
                            if (item.id == this.id) {
                                item.name = this.name;
                                // 完成更新操作之后,需要终止循环
                                return true;
                            }
                        });
                        this.flag = false;
                    } else {
                        // 添加图书
                        var book = {};
                        book.id = this.id;
                        book.name = this.name;
                        book.date = '';
                        this.books.push(book);
                        // 清空表单
                        this.id = '';
                        this.name = '';
                    }
                    // 清空表单
                    this.id = '';
                    this.name = '';
                },
                toEdit: function (id) {
                    // 禁止修改ID
                    this.flag = true;
                    console.log(id)
                    // 根据ID查询出要编辑的数据
                    var book = this.books.filter(function (item) {
                        return item.id == id;
                    });
                    console.log(book)
                    // 把获取到的信息填充到表单
                    this.id = book[0].id;
                    this.name = book[0].name;
                },
                deleteBook: function (id) {
                    // 1、根据ID 查找元素的索引
                    var index = this.books.findIndex(function (item) {
                        return item.id == id;
                    });
                    this.books.splice(index, 1);
                    /* var book = this.books.filter(function (item) {
                        return item.id != id;
                    })
                    console.log(book); */
                }
            },
            computed: {
                total: function () {
                    return this.books.length
                }
            },
            watch: {
                name: function (val) {
                    var flag = this.books.some(function (item) {
                        return item.name == val
                    })
                    if (flag) {
                        this.submitFlag = true;
                    }
                    else {
                        this.submitFlag = false
                    }
                }
            }
        });
    </script>
</body>

</html>

3、vue组件

3.1 组件化开发概述
  • 标准
  • 分治
  • 重用
  • 组合

组件化规范 web conmponents

  • 我们希望尽可能多的重用代码
  • 自定义组件的方式也不大容易 html css js
  • 多次使用组件可能导致冲突
    vue 部分已经实现了上述规范
3.2 组件化基本使用
        Vue.component(组件名称,{
            data:组件数组,
            template:组件模板内容
        })
  • 组件可以重复调用
  • 每个组件的数据互不影响 各自独立
    <div id="app">
        <button-counter></button-counter>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        /*         Vue.component(组件名称,{
                    data:组件数组,
                    template:组件模板内容
                }) */
        Vue.component('button-counter', {
            data: function () {
                // data 里面放的是 组件的数据,是一个函数,return 返回一个对象,把数据放在这个对象里面
                return {
                    count: 0
                }
            },
            template: '<button @click="handle">点击了{{count}}</button>    ',
            methods: {
                handle: function () {
                    this.count++
                }
            }
        })
        var vm = new Vue({
            el: '#app',
            data: {

            }
        })
    </script>
3.3 组件注册 注意事项 上
  • data 必须是一个函数
  • 组件模板内容必须是单个根元素(最外层不能有兄弟元素,比如 ’ ',这样就是错误的)
  • 组件模板内容可以是模板字符串
3.4 组件注册 注意事项 下 组件命名方式

组件命名的方式
1、短横线方式

Vue.component('my-component',{……})

2、驼峰方式

Vue.component('MyComponent',{……})
  • 如果使用驼峰式命名组件,那么只能在字符串模板中 用 驼峰命名的方式使用组件
  • 驼峰命名的组件,不能出现在 vue 实例的根元素中
    <div id="app">
        <button-counter></button-counter>
				<!-- 上面的写法 正确 -->
        <HelloContent></HelloContent>
        <!-- 上面的写法就是错误 -->
    </div>
3.5 局部组件注册方式

局部组件只能再注册它的父组件中使用,不能在全局组件中使用

    <div id="app">
        <hello-world></hello-world>
        <hello-tom></hello-tom>
        <hello-jerry></hello-jerry>
        <!-- 
            hello world
            hello tom
            hello jerry
         -->
    </div>
    <script src="./js/vue.js"></script>
    <script>
        var HelloWorld = {
            data: function () {
                return {
                    msg: 'hello world'
                }
            },
            template: `<div>{{msg}}</div>   `
        }
        var HelloTom = {
            data: function () {
                return {
                    msg: 'hello tom'
                }
            },
            template: `<div>{{msg}}</div>  `
        }
        var HelloJerry = {
            data: function () {
                return {
                    msg: 'hello Jerry'
                }
            },
            template: `<div>{{msg}}</div>   `
        }
        var vm = new Vue({
            el: '#app',
            data: {

            },
            components: {
                'hello-world': HelloWorld,
                'hello-tom': HelloTom,
                'hello-jerry': HelloJerry,
            }
        })
    </script>
3.6 父组件向子组件传值-基本用法

props 是单项数据流,只允许 父组件给子组件传值

子组件通过 props 接收父组件传递过来的值
父组件通过 属性值 将值传递给子组件

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

<menu-item title="来自父组件的数据"></menu-item>
<menu-item :title="title"></menu-item>
<body>
    <div id="app">
        <!-- 在这里,app 就相当于是 父组件 menu-item 就是子组件-->
        <div>{{pmsg}}</div>
        <menu-item title="来自父组件的值"></menu-item>
        <menu-item :title="ptitle"></menu-item>
        <div>传多个值</div>
        <menu-item :title="ptitle" content="hello"></menu-item>
        <!-- 
            父组件的内容
            子组件本身的数据---来自父组件的值-- - undefined
            子组件本身的数据---动态绑定属性-- - undefined
            传多个值
            子组件本身的数据---动态绑定属性-- - hello
         -->
    </div>
    <script src="./js/vue.js"></script>
    <script>
        Vue.component('menu-item', {
            props: ['title', 'content'],
            data: function () {
                return {
                    msg: '子组件本身的数据',

                }
            },
            template: '<div>{{msg +"---"+title+"-- - "+content}}</div>'
        })
        var vm = new Vue({
            el: '#app',
            data: {
                pmsg: '父组件的内容',
                ptitle: '动态绑定属性'
            },
        })
    </script>
</body>
3.7 父组件向子组件传值 props 属性命名规则
  • 在 props 中使用 驼峰形式,在html标签中必须使用 短横线的形式
  • 字符串形式的模板中没有这个限制
//在html中是短横线方式的
<menu-item menu-title="你好"></menu-item>
Vue.conponents('menu-item',{
  // 在 JavaScript 中是驼峰形式的
  props:['menuTitle'],
  template:'<div>{{menuTitle}}</div>'
})
<body>
    <div id="app">
        <!-- 在这里,app 就相当于是 父组件 menu-item 就是子组件-->
        <div>{{pmsg}}</div>
        <menu-item my-title="来自父组件的值"></menu-item>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        Vue.component('menu-item', {
            props: ['MyTitle', 'content'],
            data: function () {
                return {
                    msg: '子组件本身的数据',

                }
            },
            template: '<div>{{msg +"---"+MyTitle}}</div>'
        })
        var vm = new Vue({
            el: '#app',
            data: {
                pmsg: '父组件的内容',
                ptitle: '动态绑定属性'
            },
        })
    </script>
</body>
3.8 父组件向子组件传值 props 属性值类型 必须加:
  • 字符串
  • 数值
  • 布尔值
  • 数组
  • 对象

布尔和数值 通过 v-bind 绑定 得到到都是对应的类型,不是通过v-bind 则得到的都是字符串类型

建议传值采用 v-bind进行传值,并且等号右边加引号

<body>
    <div id="app">
        <!-- 在这里,app 就相当于是 父组件 menu-item 就是子组件-->
        <div>{{pmsg}}</div>
        <!-- 
            建议 采用 v-bind:href=""  并且值用引号

            对于 数字类型和布尔类型的数据
            去掉冒号 传递过去的是字符串
            加上冒号 传递过去的是数值类型
         -->
        <menu-item :pstr='pstr' :pnum='12' :pboo='true' :parr='parr' :pobj='pobj'></menu-item>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        Vue.component('menu-item', {
            props: ['pstr', 'pnum', 'pboo', 'parr', 'pobj'],
            data: function () {
                return {
                    msg: '子组件本身的数据',

                }
            },
            template: `
                <div>
                    <div>{{pstr}}</div>    
                    <div>{{pnum}}</div>    
                    <div>{{pboo}}</div>
                    <ul>
                        <li v-for='(item,index) in parr'>{{item}}</li>
                    </ul>  
                    <div>
                        <span>{{pobj.name}}</span>
                        <span>{{pobj.age}}</span>
                    </div>  
                </div>
            `
        })
        var vm = new Vue({
            el: '#app',
            data: {
                pmsg: '父组件的内容',
                pstr: 'hello',
                parr: ['apple', 'orange', 'banner'],
                pobj: {
                    name: 'lisi',
                    age: 12,
                }

            },
        })
    </script>
</body>
3.9 子组件向父组件传值
<body>
    <div id="app">
        <div :style="{fontSize:fontsize+'px'}">{{msg}}</div>
        <menu-item @click-fontsize="handle"></menu-item>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        Vue.component('menu-item', {
            template: `
            <button @click='$emit("click-fontsize")''>点击我 扩大父组件的字体大小</button>
            `
        })
        var vm = new Vue({
            el: '#app',
            data: {
                msg: '我是父组件内容',
                fontsize: 14

            },
            methods: {
                handle: function () {
                    this.fontsize += 5
                }
            }
        })
    </script>
</body>
3.10 子组件向父组件传值,携带参数
<body>
    <div id="app">
        <div :style="{fontSize:fontsize+'px'}">{{msg}}</div>
        <menu-item @click-fontsize="handle($event)"></menu-item>
        <!-- $event这个名字是固定的 -->
    </div>
    <script src="./js/vue.js"></script>
    <script>
        Vue.component('menu-item', {
            template: `
            <button @click='$emit("click-fontsize",10)'>点击我 扩大父组件的字体大小</button>
            `
            // $emit('第一个参数是事件名称','第二个参数是值') 
        })
        var vm = new Vue({
            el: '#app',
            data: {
                msg: '我是父组件内容',
                fontsize: 14

            },
            methods: {
                handle: function (val) {
                    this.fontsize += val
                }
            }
        })
    </script>
</body>
<body>
    <div id="app">
        <div :style="{fontSize:fontsize+'px'}">{{msg}}</div>
        <menu-item @change-zi="handle($event)"></menu-item>
        <!-- $event这个名字是固定的 -->
    </div>
    <script src="./js/vue.js"></script>
    <script>
        Vue.component('menu-item', {
            template: `
            <button @click='handle'>点击我 扩大父组件的字体大小</button>
            `
            ,
            // $emit('第一个参数是事件名称','第二个参数是值') 
            methods: {
                handle: function () {
                    this.$emit('change-zi', {
                        "first": 10,
                        "second": 20,
                        "third": 30,
                    })
                }
            }
        })
        var vm = new Vue({
            el: '#app',
            data: {
                msg: '我是父组件内容',
                fontsize: 14

            },
            methods: {
                handle: function (val) {
                    console.log(val);
                  // {first: 10, second: 20, third: 30}
                    this.fontsize += val.first
                }
            }
        })
    </script>
</body>
3.11 兄弟组件之间的传值

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>{{msg}}</div>
        <test-tom></test-tom>
        <test-jerry></test-jerry>
        <div @click='handle'>销毁</div>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        //  提供事件中心
        var hub = new Vue();

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

            },
            methods: {
                handle: function () {
                    hub.$off('tom-event')
                    hub.$off('jerry-event')
                }
            }
        })
    </script>
</body>
3.12 组件插槽基本用法

父组件向子组件传递 内容

<body>
    <div id="app">
        <test-item>插槽的内容</test-item>
        <!-- 标签中间的值,会传递给 slot 标签,并且覆盖掉slot标签设置的值-->
        <!-- 如果标签中间的值,没有内容,那么会显示 slot的值 -->
    </div>

    <script src="./js/vue.js"></script>
    <script>
        Vue.component('test-item', {
            template: `
            <div>
                <b>报错</b>
                <slot>222</slot>
            </div>
            `
        })
        var vm = new Vue({
            el: '#app',
            data: {

            }
        })
    </script>
</body>
3.13 具名插槽用法
<body>
    <div id="app">
        <test-item>
            <p slot="header">标题信息</p>
            <p>主体信息1</p>
            <p>主体信息2</p>
            <p slot="footer">底部信息</p>
        </test-item>
        <!-- 
            结果
            header 包含 一个 标题信息
            main 包含两个 p
            footer 包含 一个 底部信息
         -->

        <!-- 更高级的用法 -->
        <!-- template 标签只是起一个临时性包裹的作用 -->
        <test-item>
            <template slot="header">
                <p>标题信息1</p>
                <p>标题信息2</p>
            </template>
            <p>主体信息1</p>
            <p>主体信息2</p>
            <template slot="footer">
                <p>底部信息1</p>
                <p>底部信息2</p>
            </template>
        </test-item>
    </div>

    <script src="./js/vue.js"></script>
    <script>
        Vue.component('test-item', {
            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>
3.14 作用域插槽

父组件对子组件的内容进行加功处理

<body>
    <div id="app">
        <test-item :list='list'>
            <template slot-scope='slotProps'>
                <!-- 这个名字 是自定义的 -->
                <b v-if='slotProps.info.id==2'>{{slotProps.info.name}}</b>
                <span v-else>{{slotProps.info.name}}</span>
                <!-- slotProps 可以得到子组件传递来的数据 -->

            </template>
        </test-item>
    </div>

    <script src="./js/vue.js"></script>
    <script>
        Vue.component('test-item', {
            props: ['list'],
            template: `
            <div>
               <li v-for='(item,index) in list'>
                <slot :info='item'>{{item.name}}</slot>
                </li>
            </div>
            `
        })
        var vm = new Vue({
            el: '#app',
            data: {
                list: [{
                    id: 1,
                    name: 'apple'
                }, {
                    id: 2,
                    name: 'orange'
                }, {
                    id: 3,
                    name: 'banner'
                },]
            }
        })
    </script>
</body>

4、购物车案例

4.1 购物车结算页面

组件化开发
1、标题组件(展示文本)
2、列表组件(列表展示、商品数量变更、商品删除)
3、结算组件(计算商品总额)

4.2 组件化布局

1、功能实现步骤

  • 实现整体布局和样式效果
  • 划分独立的功能组件
  • 组合所有的子组件形成整体结构
  • 逐个实现各个组件功能
  • 标题组件
  • 列表组件
  • 结算组件
<body>
    <div id="app">
        <div class="container">
            <my-cart></my-cart>
        </div>
    </div>
    <script type="text/javascript" src="./js/vue.js"></script>
    <script type="text/javascript">
        var CartTile = {
            template: `
            <div class="title">我的商品</div>
        `
        }
        var CartList = {
            template: `
            <div>
                    <div class="item">
                        <img src="img/a.jpg" />
                        <div class="name"></div>
                        <div class="change">
                            <a href="">-</a>
                            <input type="text" class="num" />
                            <a href="">+</a>
                        </div>
                        <div class="del">×</div>
                    </div>
                    <div class="item">
                        <img src="img/b.jpg" />
                        <div class="name"></div>
                        <div class="change">
                            <a href="">-</a>
                            <input type="text" class="num" />
                            <a href="">+</a>
                        </div>
                        <div class="del">×</div>
                    </div>
                    <div class="item">
                        <img src="img/c.jpg" />
                        <div class="name"></div>
                        <div class="change">
                            <a href="">-</a>
                            <input type="text" class="num" />
                            <a href="">+</a>
                        </div>
                        <div class="del">×</div>
                    </div>
                    <div class="item">
                        <img src="img/d.jpg" />
                        <div class="name"></div>
                        <div class="change">
                            <a href="">-</a>
                            <input type="text" class="num" />
                            <a href="">+</a>
                        </div>
                        <div class="del">×</div>
                    </div>
                    <div class="item">
                        <img src="img/e.jpg" />
                        <div class="name"></div>
                        <div class="change">
                            <a href="">-</a>
                            <input type="text" class="num" />
                            <a href="">+</a>
                        </div>
                        <div class="del">×</div>
                    </div>
                </div>
        `
        }
        var CartTotal = {
            template: `
            <div class="total">
                    <span>总价:123</span>
                    <button>结算</button>
                </div>
        `
        }
        Vue.component('my-cart', {
            template: `
           
            <div class="cart">
                <cart-title></cart-title>
                <cart-list></cart-list>
                <cart-total></cart-total>

            </div>
            `,
            components: {
                'cart-title': CartTile,
                'cart-list': CartList,
                'cart-total': CartTotal,
            }
        })
        var vm = new Vue({
            el: '#app',
            data: {

            }
        });

    </script>
4.3 实现标题和结算组件功能

实现的功能 标题 和 总价计算

   <script type="text/javascript">
        var CartTile = {
            // 得到父组件传递来的数据
            props: ['username'],
            template: `
            <div class="title">{{username}}的商品</div>
        `
        }
        var CartList = {
            template: `
            <div>
                    <div class="item">
                        <img src="img/a.jpg" />
                        <div class="name"></div>
                        <div class="change">
                            <a href="">-</a>
                            <input type="text" class="num" />
                            <a href="">+</a>
                        </div>
                        <div class="del">×</div>
                    </div>
                    <div class="item">
                        <img src="img/b.jpg" />
                        <div class="name"></div>
                        <div class="change">
                            <a href="">-</a>
                            <input type="text" class="num" />
                            <a href="">+</a>
                        </div>
                        <div class="del">×</div>
                    </div>
                    <div class="item">
                        <img src="img/c.jpg" />
                        <div class="name"></div>
                        <div class="change">
                            <a href="">-</a>
                            <input type="text" class="num" />
                            <a href="">+</a>
                        </div>
                        <div class="del">×</div>
                    </div>
                    <div class="item">
                        <img src="img/d.jpg" />
                        <div class="name"></div>
                        <div class="change">
                            <a href="">-</a>
                            <input type="text" class="num" />
                            <a href="">+</a>
                        </div>
                        <div class="del">×</div>
                    </div>
                    <div class="item">
                        <img src="img/e.jpg" />
                        <div class="name"></div>
                        <div class="change">
                            <a href="">-</a>
                            <input type="text" class="num" />
                            <a href="">+</a>
                        </div>
                        <div class="del">×</div>
                    </div>
                </div>
        `
        }
        var CartTotal = {
            props: ['list'],
            // 获取父组件传来的 list 列表
            template: `
            <div class="total">
                    <span>总价:{{returnPrice}}</span>
                    <button>结算</button>
                </div>
        `,
            methods: {

            },
            computed: {
                returnPrice: function () {
                    var sum = 0
                    this.list.forEach((value, index) => {
                        sum += value.price * value.num
                    });
                    return sum
                }
            }

        }
        Vue.component('my-cart', {
            data: function () {
                return {
                    username: '张三',
                    list: [{
                        id: 1,
                        name: 'TCL彩电',
                        price: 1000,
                        num: 1,
                        img: 'img/a.jpg'
                    }, {
                        id: 2,
                        name: '机顶盒',
                        price: 1000,
                        num: 1,
                        img: 'img/b.jpg'
                    }, {
                        id: 3,
                        name: '海尔冰箱',
                        price: 1000,
                        num: 1,
                        img: 'img/c.jpg'
                    }, {
                        id: 4,
                        name: '小米手机',
                        price: 1000,
                        num: 1,
                        img: 'img/d.jpg'
                    }, {
                        id: 5,
                        name: 'PPTV电视',
                        price: 1000,
                        num: 2,
                        img: 'img/e.jpg'
                    }]
                    //  list 商品列表

                }
            },
            template: `
           
            <div class="cart">
                <cart-title :username='username'></cart-title>
                <cart-list></cart-list>
                <cart-total :list='list'></cart-total>

            </div>
            `,
            components: {
                'cart-title': CartTile,
                'cart-list': CartList,
                'cart-total': CartTotal,
            }
        })
        var vm = new Vue({
            el: '#app',
            data: {

            }
        });

    </script>
        
4.4 删除商品功能
  • 父组件给子组件传递list 列表,商品采用 v-for 渲染list列表
  • 删除 数据,应该在父组件进行,在子组件中拿到id,把id 传递给父组件
        var CartList = {
            props: ['list'],
            methods: {
                del: function (id) {
                    // 把 id 传递给父组件
                    this.$emit('cart-del', id)
                }
            },
            template: `
            <div>
                    <div :key='item.id' v-for='item in list' class="item">
                        <img :src="item.img" />
                        <div class="name">{{item.name}}</div>
                        <div class="change">
                            <a href="">-</a>
                            <input type="text" class="num" />
                            <a href="">+</a>
                        </div>
                        <div class="del" @click.prevent='del(item.id)'>×</div>
                    </div>
                   
                </div>
        `
        }
        Vue.component('my-cart', {
            data: function () {
                return {
                    username: '张三',
                    list: [{
                        id: 1,
                        name: 'TCL彩电',
                        price: 1000,
                        num: 1,
                        img: 'img/a.jpg'
                    }, {
                        id: 2,
                        name: '机顶盒',
                        price: 1000,
                        num: 1,
                        img: 'img/b.jpg'
                    }, {
                        id: 3,
                        name: '海尔冰箱',
                        price: 1000,
                        num: 1,
                        img: 'img/c.jpg'
                    }, {
                        id: 4,
                        name: '小米手机',
                        price: 1000,
                        num: 1,
                        img: 'img/d.jpg'
                    }, {
                        id: 5,
                        name: 'PPTV电视',
                        price: 1000,
                        num: 2,
                        img: 'img/e.jpg'
                    }]
                    //  list 商品列表

                }
            },
            template: `
           
            <div class="cart">
                <cart-title :username='username'></cart-title>
                <cart-list :list='list' @cart-del='delCart($event)'></cart-list>
                <cart-total :list='list'></cart-total>

            </div>
            `,
            components: {
                'cart-title': CartTile,
                'cart-list': CartList,
                'cart-total': CartTotal,
            },
            methods: {
                delCart: function (id) {
                    // 根据 id 删除 list对应的数据
                    // 1、根据 id 找到对应的索引
                    var index = this.list.findIndex(item => {
                        return item.id == id
                    })
                    // 2、根据 索引 删除
                    this.list.splice(index, 1)
                }
            }
        })
4.5 实现列表组件更新商品功能 上 emit传递多个参数

注意 当 emit 需要传递多个参数的时候,可以用对象的形式

       var CartList = {
            props: ['list'],
            methods: {
                del: function (id) {
                    // 把 id 传递给父组件
                    this.$emit('cart-del', id)
                },
                changeNum: function (id, event) {
                    // event.target.value 可以获取当前项输入的值
                    this.$emit('input-num', {
                        id: id,
                        num: event.target.value,
                    })
                }
            },
            template: `
            <div>
                    <div :key='item.id' v-for='item in list' class="item">
                        <img :src="item.img" />
                        <div class="name">{{item.name}}</div>
                        <div class="change">
                            <a href="">-</a>
                            <input type="text" class="num" :value='item.num' @blur='changeNum(item.id,$event)' />
                            <a href="">+</a>
                        </div>
                        <div class="del" @click.prevent='del(item.id)'>×</div>
                    </div>
                   
                </div>
        `
        
        Vue.component('my-cart', {
            data: function () {
                return {
                    username: '张三',
                    list: [{
                        id: 1,
                        name: 'TCL彩电',
                        price: 1000,
                        num: 1,
                        img: 'img/a.jpg'
                    }, {
                        id: 2,
                        name: '机顶盒',
                        price: 1000,
                        num: 1,
                        img: 'img/b.jpg'
                    }, {
                        id: 3,
                        name: '海尔冰箱',
                        price: 1000,
                        num: 1,
                        img: 'img/c.jpg'
                    }, {
                        id: 4,
                        name: '小米手机',
                        price: 1000,
                        num: 1,
                        img: 'img/d.jpg'
                    }, {
                        id: 5,
                        name: 'PPTV电视',
                        price: 1000,
                        num: 2,
                        img: 'img/e.jpg'
                    }]
                    //  list 商品列表

                }
            },
            template: `
           
            <div class="cart">
                <cart-title :username='username'></cart-title>
                <cart-list :list='list' @cart-del='delCart($event)' @input-num='inputChange($event)'></cart-list>
                <cart-total :list='list'></cart-total>

            </div>
            `,
            components: {
                'cart-title': CartTile,
                'cart-list': CartList,
                'cart-total': CartTotal,
            },
            methods: {
                delCart: function (id) {
                    // 根据 id 删除 list对应的数据
                    // 1、根据 id 找到对应的索引
                    var index = this.list.findIndex(item => {
                        return item.id == id
                    })
                    // 2、根据 索引 删除
                    this.list.splice(index, 1)
                },
                inputChange: function (numObj) {
                    var index = this.list.findIndex(item => {
                        return item.id == numObj.id
                    })
                    this.list[index].num = numObj.num
                }
            }
        })

4.6 实现列表组件更新商品功能 下 加号 减号 emit传递多个参数

一个事件,包含三个处理程序
完整代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style type="text/css">
        .container {}

        .container .cart {
            width: 300px;
            /*background-color: lightgreen;*/
            margin: auto;
        }

        .container .title {
            background-color: lightblue;
            height: 40px;
            line-height: 40px;
            text-align: center;
            /*color: #fff;*/
        }

        .container .total {
            background-color: #FFCE46;
            height: 50px;
            line-height: 50px;
            text-align: right;
        }

        .container .total button {
            margin: 0 10px;
            background-color: #DC4C40;
            height: 35px;
            width: 80px;
            border: 0;
        }

        .container .total span {
            color: red;
            font-weight: bold;
        }

        .container .item {
            height: 55px;
            line-height: 55px;
            position: relative;
            border-top: 1px solid #ADD8E6;
        }

        .container .item img {
            width: 45px;
            height: 45px;
            margin: 5px;
        }

        .container .item .name {
            position: absolute;
            width: 90px;
            top: 0;
            left: 55px;
            font-size: 16px;
        }

        .container .item .change {
            width: 100px;
            position: absolute;
            top: 0;
            right: 50px;
        }

        .container .item .change a {
            font-size: 20px;
            width: 30px;
            text-decoration: none;
            background-color: lightgray;
            vertical-align: middle;
        }

        .container .item .change .num {
            width: 40px;
            height: 25px;
        }

        .container .item .del {
            position: absolute;
            top: 0;
            right: 0px;
            width: 40px;
            text-align: center;
            font-size: 40px;
            cursor: pointer;
            color: red;
        }

        .container .item .del:hover {
            background-color: orange;
        }
    </style>
</head>

<body>
    <div id="app">
        <div class="container">
            <my-cart></my-cart>
        </div>
    </div>
    <script type="text/javascript" src="./js/vue.js"></script>
    <script type="text/javascript">
        var CartTile = {
            // 得到父组件传递来的数据
            props: ['username'],
            template: `
            <div class="title">{{username}}的商品</div>
        `
        }
        var CartList = {
            props: ['list'],
            methods: {
                del: function (id) {
                    // 把 id 传递给父组件
                    this.$emit('cart-del', id)
                },
                changeNum: function (id, event) {
                    // event.target.value 可以获取当前项输入的值
                    this.$emit('change-num', {
                        type: 'change',
                        id: id,
                        num: parseInt(event.target.value),
                    })
                },
                numAdd: function (id) {
                    this.$emit('change-num', {
                        id: id,
                        type: 'add'
                    })
                },
                numSub: function (id) {
                    this.$emit('change-num', {
                        id: id,
                        type: 'sub'
                    })
                },
            },
            template: `
            <div>
                    <div :key='item.id' v-for='item in list' class="item">
                        <img :src="item.img" />
                        <div class="name">{{item.name}}</div>
                        <div class="change">
                            <a href="" @click.prevent='numSub(item.id)'>-</a>
                            <input type="text" class="num" :value='item.num' @blur='changeNum(item.id,$event)' />
                            <a href="" @click.prevent='numAdd(item.id)'>+</a>
                        </div>
                        <div class="del" @click.prevent='del(item.id)'>×</div>
                    </div>
                   
                </div>
        `
        }
        var CartTotal = {
            props: ['list'],
            // 获取父组件传来的 list 列表
            template: `
            <div class="total">
                    <span>总价:{{returnPrice}}</span>
                    <button>结算</button>
                </div>
        `,
            methods: {

            },
            computed: {
                returnPrice: function () {
                    var sum = 0
                    this.list.forEach((value, index) => {
                        sum += value.price * value.num
                    });
                    return sum
                }
            }

        }
        Vue.component('my-cart', {
            data: function () {
                return {
                    username: '张三',
                    list: [{
                        id: 1,
                        name: 'TCL彩电',
                        price: 1000,
                        num: 1,
                        img: 'img/a.jpg'
                    }, {
                        id: 2,
                        name: '机顶盒',
                        price: 1000,
                        num: 1,
                        img: 'img/b.jpg'
                    }, {
                        id: 3,
                        name: '海尔冰箱',
                        price: 1000,
                        num: 1,
                        img: 'img/c.jpg'
                    }, {
                        id: 4,
                        name: '小米手机',
                        price: 1000,
                        num: 1,
                        img: 'img/d.jpg'
                    }, {
                        id: 5,
                        name: 'PPTV电视',
                        price: 1000,
                        num: 2,
                        img: 'img/e.jpg'
                    }]
                    //  list 商品列表

                }
            },
            template: `
           
            <div class="cart">
                <cart-title :username='username'></cart-title>
                <cart-list :list='list' @cart-del='delCart($event)' @change-num='inputChange($event)'></cart-list>
                <cart-total :list='list'></cart-total>

            </div>
            `,
            components: {
                'cart-title': CartTile,
                'cart-list': CartList,
                'cart-total': CartTotal,
            },
            methods: {
                delCart: function (id) {
                    // 根据 id 删除 list对应的数据
                    // 1、根据 id 找到对应的索引
                    var index = this.list.findIndex(item => {
                        return item.id == id
                    })
                    // 2、根据 索引 删除
                    this.list.splice(index, 1)
                },
                inputChange: function (numObj) {
                    // 我们要区别这三种类型
                    // 输入域变更
                    if (numObj.type == 'change') {
                        var index = this.list.findIndex(item => {
                            return item.id == numObj.id
                        })
                        this.list[index].num = numObj.num
                    }
                    else if (numObj.type == 'sub') {
                        var index = this.list.findIndex(item => {
                            return item.id == numObj.id
                        })
                        this.list[index].num -= 1
                    }
                    else if (numObj.type == 'add') {
                        var index = this.list.findIndex(item => {
                            return item.id == numObj.id
                        })
                        this.list[index].num += 1
                    }
                    // 加号 变更

                    // 减号变更

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

            }
        });

    </script>
</body>

</html>

5、Promise

5.1 学习目标
  • 能够说出什么是前后端交互模式
  • 能够说出 promise 的相关概念和用法
  • 能够使用 fetch 进行接口调用 标准化组织提出的
  • 能够使用 axios 进行接口调用 第三方的库
  • 能够使用 async / await 方式调用接口 es7
  • 能够基于后台接口实现案例
5.2 前后端交互概述与 URL 地址格式

1、接口调用方式

  • 原生Ajax
  • 基于 jQuery 的Ajax 侧重DOM
  • fetch Ajax的升级版,也是标准化组织的新规范
  • axios比fetch 更加强大

2、 url地址格式

协议、端口、域名、地址、查询参数、锚点

5.3 异步编程问题与 Promise 概述
  • 异步效果分析
    1. 定时任务
    2. Ajax
    3. 事件函数
  • 多次异步调用的依赖分析
    • 多次异步调用的 结果顺序不确定,需要根据相应的因素
    • 异步调用结果如果存在依赖,需要进行嵌套,容易出现回调地狱!
$.ajax({
  ulr:'http://www1',
  success:function(res){
    console.log('1')
  }
})
$.ajax({
  ulr:'http://www1',
  success:function(res){
    console.log('1')
  }
})
$.ajax({
  ulr:'http://www1',
  success:function(res){
    console.log('1')
  }
})
// 他们三个的输出 顺序不会固定,若请求的慢,则输出的 相对而言比较晚

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

  • 可以避免多层异步调用 嵌套问题(回调地狱)
  • Promise 对象提供了简洁的API ,使得控制异步操作更加容易
5.4 Promise 基本用法
  • 实例化 Promise 对象,构造函数中传递函数,该函数中用于处理异步任务
  • resolve 和 reject 两个参数用于处理成功和失败两种情况,并通过 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) {
            // 成功 调用 resolve()
            // 失败 调用 reject()
            // 这里用于实现 异步任务
            setTimeout(function () {
                var flag = true
                if (flag) {
                    // 正常情况
                    resolve('Hello')
                }
                else {
                    reject('出错了')
                }
            }, 1000)
        })
        p.then(function (ret) {
            // 从 resolve 得到的 成功的结果
            console.log(ret);
        }, function (ret) {
            // 从 reject 得到的 失败的结果
            console.log(ret);
        })
// 最后输出的结果是  hello  
5.5 Promise 发送 Ajax请求并处理回调地狱问题
        function queryData(url) {
            var p = new Promise(function (resolve, reject) {
                // 成功 调用 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://127.0.0.1:3000/data')
            .then(function (ret) {
                // 从 resolve 得到的 成功的结果
                console.log(ret);
                return queryData('http://127.0.0.1:3000/data1')
            }, function (ret) {
                // 从 reject 得到的 失败的结果
                console.log(ret);
            })
            .then(function (ret) {
                console.log(ret); // data1 的返回结果
            })
5.6 Promise 的 then方法参数中的函数的返回值

then 参数中的函数返回值

1、返回 Promise 实例对象

返回的该实例对象会调用 下一个then

2、返回普通值

返回的普通值 会直接传递给 下一个then,通过 then 参数中函数的参数接收该值

        function queryData(url) {
            var p = new Promise(function (resolve, reject) {
                // 成功 调用 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://127.0.0.1:3000/data')
            .then(function (ret) {
                // 从 resolve 得到的 成功的结果
                console.log(ret);
                return queryData('http://127.0.0.1:3000/data1')
            }, function (ret) {
                // 从 reject 得到的 失败的结果
                console.log(ret);
            })
            .then(function (ret) {
                console.log(ret); // data1 的返回结果
                return new Promise(function (resolve, reject) {
                    setTimeout(function () {
                        resolve(111111)
                    }, 1000)
                })
            })
            .then(function (data) {
                console.log(data);// 111
                return 'Hello'
                // 返回普通值,默认的 promise 实例对象 继续调用
            })
            .then(function (data) {
                console.log(data); // Hello
            })
5.7 Promise 常用的API

1、实例方法 都在 Promise的原型中

  • p.then() 得到异步任务的正确结果
  • p.catch() 获取异常信息
  • p.finally() 成功与否都会执行

catch 是可以扑捉到 resolve reject 的异常; reject 只能扑捉到 reject的异常

        function queryData(url) {
            var p = new Promise(function (resolve, reject) {
                // 成功 调用 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://127.0.0.1:3000/data11')
            .then(function (ret) {
                // 从 resolve 得到的 成功的结果
                console.log(ret);
            })
            .catch(function (ret) {
                // 获取异常信息
                // catch 是可以扑捉到 resolve reject 的异常
                // reject 只能扑捉到 reject的异常
                console.log(ret);
            })
            .finally(function () {
                // 不论执行失败还是成功,都会执行
                console.log('执行完毕');
            })
5.8 Promise 常用 API 对象方法

直接通过函数名称调用的,在Promise 里面的

  • Promise.call() 并发处理多个异步任务,所有任务都执行完成才能得到结果
  • Promise.race() 并发处理多个异步任务,只要有一个任务完成就能得到结果
        function queryData(url) {
            var p = new Promise(function (resolve, reject) {
                // 成功 调用 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
        }
        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 (results) {
            console.log(results);
            // ["Hello TOM!", "Hello JERRY!", "Hello SPIKE!"]
        })
        Promise.race([p1, p2, p3]).then(function (results) {
            console.log(results);
            // Hello Tom
            // 请求都发出去了,只会得到 最先返回的结果
        })

6、fetch

6.1 fetch 概述
  • 更加简单的数据获取方式,功能更加强大,可以看作是 xhr的升级版
  • 基于 Promise 实现

语法结构

fetch(url).then(fn2).then(fn3)…….catch(fn)
    <script>
        fetch('http://localhost:3000/fdata').then(function (data) {
            // 这里的data 不能直接拿到数据
          	// text 方法 是 fetchAPI 的一部分
          	// text 用户获取后台返回的数据
            return data.text()
            // data.text() 返回的是 Promise实例对象

        }).then(function (data) {
            console.log(data);
        })
    </script>
6.2 fetch 的 get 和 post 请求

1、常用配置选项

  • method(String) HTTP请求方法,默认为 get
  • body(String) HTTP 的请求参数
  • headers(Object) http 的请求头,默认为 {}

delete 和 get 请求方式,大体一样,只是 method 不同

        fetch('http://localhost:3000/books?id=123', {
            method: 'get',

        }).then(function (data) {
            // 这里的data 不能直接拿到数据
            return data.text()
            // data.text() 返回的是 Promise实例对象

        }).then(function (data) {
            console.log(data);
        })
        // 第二种方式
        fetch('http://localhost:3000/books/123', {
            method: 'get',

        }).then(function (data) {
            // 这里的data 不能直接拿到数据
            return data.text()
            // data.text() 返回的是 Promise实例对象

        }).then(function (data) {
            console.log(data);
        })
6.3 fetch 的post put

post put 需要设置额外的 body 和 headers

        fetch('http://localhost:3000/books', {
            method: 'post',
            body: 'uname=lisi&pwd=123',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
                // 也可以设置成 json 格式,前提是 把body的内容转化为 json的数据
            }
        }).then(function (data) {
            // 这里的data 不能直接拿到数据
            return data.text()
            // data.text() 返回的是 Promise实例对象

        }).then(function (data) {
            console.log(data);
        })
fetch 响应结果
  • text() 将返回体处理成字符串类型
  • json() 将返回结果 和 JSON.parse(response Text) 一样
        fetch('http://localhost:3000/json', {
        }).then(function (data) {
            // 这里的data 不能直接拿到数据
            return data.json()
           // 不写 json 写 text 返回的是字符串
            // data.text() 返回的是 Promise实例对象

        }).then(function (data) {
            console.log(data);
            //{uname: "lisi", age: 13, gender: "male"}
        })

7、axios

7.1 概述

axios(官网:https://github.com/axios/axios/)是一个基于 Promise 用于浏览器 和 node.js 的 HTTP客户端

  • 支持浏览器和 node.js
  • 支持 promise
  • 能拦截请求和响应
  • 自动转换 JSON 数据
        axios.get('http://localhost:3000/adata').then(function (ret) {
            // ret.data  才是后台接口返回的数据,data 是固定的属性,用于获取接口返回的实际数据
            console.log(ret);
            console.log(ret.data);
        })
7.2 axios get传参

get

  • 通过 url直接传递
  • 通过 params 传参
    • 第一种 http://localhost/axios/123
    • 第二种,通过对象方式传参 这种更常用
        axios.get('http://localhost:3000/axios', {
            params: {
                id: 789
            }
        }).then(function (ret) {
            // ret.data  才是后台接口返回的数据,data 是固定的属性,用于获取接口返回的实际数据
            console.log(ret);
            console.log(ret.data);
        })
        axios.get('http://localhost:3000/axios/345').then(function (ret) {
            // ret.data  才是后台接口返回的数据,data 是固定的属性,用于获取接口返回的实际数据
            console.log(ret);
            console.log(ret.data);
        })
        axios.get('http://localhost:3000/axios?id=2', {
            params: {
                id: 789
            }
        }).then(function (ret) {
            // ret.data  才是后台接口返回的数据,data 是固定的属性,用于获取接口返回的实际数据
            console.log(ret);
            console.log(ret.data);
        })
7.3 axios post 传参
  • 一种是 json 形式的
  • 一种 是 表单形式de
// 默认传递的是 json 格式的数据
axios.post('/adara',{
  uname:'tom',
  pwd:123
}).then(ret=>{
  console.log(ret.data)
})
        axios.post('http://localhost:3000/axios', {
            uname: 'lisis',
            pwd: '123'
        }).then(function (ret) {
            // ret.data  才是后台接口返回的数据,data 是固定的属性,用于获取接口返回的实际数据
            console.log(ret.data);
        })

传递 表单形式的数据

        const params = new URLSearchParams();
        params.append('uname', 'zhang')
        params.append('pwd', '111')
        axios.post('http://localhost:3000/axios', params).then(ret => {
            console.log(ret.data)
        })
7.4 axios 响应结果与全局配置

响应结果

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

全局配置

        axios.defaults.headers['mytoken'] = 'hello' // 配置请求头
        axios.defaults.timeout = 3000 // 设置超时
        axios.defaults.baseURL = 'http://localhost:3000/' // 设置基准URL地址,再写请求的时候,只需要写请求路径就行了
        axios.post('axios', {
            uname: 'lisis',
            pwd: '123'
        }).then(function (ret) {
            // ret.data  才是后台接口返回的数据,data 是固定的属性,用于获取接口返回的实际数据
            console.log(ret.data);
        })
7.5 axios 拦截器用法

1、请求拦截器

再发请求之前设置一些信息,常用于判断是否添加请求头

        axios.interceptors.request.use(function (config) {
            config.headers.mytoken = 'nihao'
            // 必须要 return出去
            return config
        }, function (err) {
            console.log(err);
        })

2、响应拦截器

        axios.interceptors.response.use(function (res) {
            // res 就是响应回来的东西 ,res.data 才是响应回来的数据
            var data = res.data
            // 这样设置表示,接口响应回来的res 都是 直接的数据,不需要再通过 .data 获取数据了
            // 必须要 return出去
            return data
        }, function (err) {
            console.log(err);
        })
7.6 async 函数基本用法
  • async / await 是 ES7引入的新语法,可以更加方便的进行异步操作
  • async 关键字用于函数上(async函数的返回值是Promise 实例对象)
  • await 关键字用于 async 函数当中 (await可以得到异步的结果)
    <script src="./js/axios.js"></script>
    <script>
        async function queryData() {
            var ret = await axios.get('http://localhost:3000/adata')
            return ret.data
        }
        queryData().then(function (data) {
            console.log(data);
        })
    </script>
7.7 async 函数处理多个异步请求
        async function queryData() {
            var info = await axios.get('http://localhost:3000/async1')
            var ret = await axios.get('http://localhost:3000/async2?info=' + info.data)
            return ret.data
        }
        queryData().then(function (res) {
            console.log(res);
        })

8、基于后台接口的图书馆案例

8.1 图书列表加载
// 给 axios 设置响应 拦截器,把返回的数据,直接修改成真正的数据
				axios.defaults.baseURL = 'http://localhost:3000/';
        axios.interceptors.response.use(function (res) {
            return res.data;
        }, function (error) {
            console.log(error)
        });

// vue   data 里面的方法
                queryData: async function () {
                    // 调用后台接口获取图书列表数据
                    // var ret = await axios.get('books');
                    // this.books = ret.data;

                    this.books = await axios.get('books');
                }

建议vue种data的methods对象种的,方法都采用 async、await的形式,这样写更加简洁

9、vue路由

9.1 vue 路由的 学习目标
  • 能够说出路由的概念
  • 能够说出 vue-router 的基本使用步骤
  • 能够说出 vue-router 的嵌套路由用法
  • 能够说出 vue-router 动态路由匹配用法
  • 能够说出 vue-router 命名路由用法
  • 能够说出 vue-router 编程式导航用法
  • 能够基于路由的方式实现业务功能
9.2 路由的基本概念

路由的本质就是对应关系

路由分为 后端路由 和 前端路由

1、后端路由

  • 概念:根据不同的 用户 URL请求 ,返回不同的内容
  • 本质:URL 请求地址 与 服务器资源之间的对应关系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1ZCl7DT5-1620387784181)(vue基础.assets/image-20201025181259535.png)]

2、SPA

  • 后端渲染(存在性能问题)
  • Ajax 前端渲染(前端渲染提高性能,但不支持浏览器的前进后退操作)
  • SPA单页面应用程序:整个网站只有一个页面,内容的变化通过 Ajax局部更新实现、同时支持浏览器地址栏的前进和后退操作
  • SPA实现原理之一:基于URL地址的 hash(hash的变化会导致浏览器记录访问历史的变化,但是 hash的变化不会触发新的 URL 请求)
  • 在实现 SPA 过程中,最核心的技术点就是前端路由

3、前端路由

  • 概念:根据不同的用户事件,显示不同的页面内容
  • 本质:用户事件与事件处理函数之间的对应关系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q6JnSNwb-1620387784182)(vue基础.assets/image-20201025183610619.png)]

9.3 实现简易的前端路由
// 监听 window 的 onhashchange 事件,根据获取到的最新的 hash值,切换要显示的组件的名称
window.onhashchange=function(){
  // 通过 location.hash 获取到最新的 hash值
}

component标签就是一个组件的占位符,:is 就是指定那个组件渲染到此处,注意is里面的值如果是写死的,必须是一个字符串才行

<body>
  <!-- 被 vue 实例控制的 div 区域 -->
  <div id="app">
    <!-- 切换组件的超链接 -->
    <a href="#/zhuye">主页</a>
    <a href="#/keji">科技</a>
    <a href="#/caijing">财经</a>
    <a href="#/yule">娱乐</a>
    <!-- 根据 :is 属性指定的组件名称,把对应的组件渲染到 component 标签所在的位置 -->
    <!-- 可以把 component 标签当做是【组件的占位符】 -->
    <component :is="comName"></component>
  </div>

  <script>
    // 主页组件
    const zhuye = {
      template: '<h1>主页信息</h1>'
    }
    // 科技组件
    const keji = {
      template: '<h1>科技信息</h1>'
    }
    // 财经组件
    const caijing = {
      template: '<h1>财经信息</h1>'
    }
    // 娱乐组件
    const yule = {
      template: '<h1>娱乐信息</h1>'
    }
    const vm = new Vue({
      el: '#app',
      data: {
        comName: 'zhuye'
      },
      // 注册私有组件
      components: {
        'zhuye': zhuye,
        'keji': keji,
        'caijing': caijing,
        'yule': yule
      }
    })
    // 监听 window 的 onhashchange 事件,根据获取到的最新的 hash 值,切换要显示的组件的名称
    window.onhashchange = function () {
      // 通过 location.hash 获取到最新的 hash 值
      console.log(location.hash);
      switch (location.hash.slice(1)) {
        case '/zhuye':
          vm.comName = 'zhuye'
          break
        case '/keji':
          vm.comName = 'keji'
          break
        case '/caijing':
          vm.comName = 'caijing'
          break
        case '/yule':
          vm.comName = 'yule'
          break
      }
    }
  </script>
</body>
9.4 Vue Router

官网 https://router.vuejs.org/zh/ 是 vue.js 的路由管理器

功能

  • 支持 HTML5 历史模式 或 hash模式
  • 支持嵌套路由
  • 支持路由参数
  • 支持编程式路由
  • 支持命名路由
9.5 vue-router 的基本使用
  • 引入相关的库文件
  • 添加路由链接
  • 添加路由填充位
  • 定义路由组件
  • 配置路由规则并创建路由实例
  • 把路由挂载到 Vue 跟实例中
# 添加路由链接
# router-link 是 vue 中提供的标签,默认会被渲染为 标签 
# to 属性 默认会被渲染为 href 属性
# to 属性的值默认会被渲染为 # 开头的 hash 地址
<router-link to='/user'> user </router-link>

# 添加路由填充位,也叫路由占位符
# 将来通过路由规则匹配到的组件,将会被渲染到 router-view 所在的位置
<router-view></router-view>

源代码

<body>
    <div id="app">
        <!-- 1、添加路由链接 -->
        <router-link to='/user'>User </router-link>
        <router-link to="/Register">Register </router-link>

        <!-- 2、定义路由填充位 -->
        <router-view></router-view>
    </div>
    <script src="./js/vue.js"></script>
    <script src="./js/vue-router.js"></script>
    <script>
        // 3、定义路由组件
        var user = {
            template: ' <h1>user 组件</h1>'
        }
        var Register = {
            template: '<h1>Register 组件</h1>'
        }
        var router = new VueRouter({
            // routes 是路由规则数组
            routes: [
                // 每个路由规则都是一个配置对象,其中至少包括 path 和component 两个属性
                // path 表示当前路由规则匹配的 hash地址
                // component 表示当前路由规则对应要展示的组件,它只接受组件对象,不接受字符串
                { path: '/user', component: user },
                { path: '/Register', component: Register },
            ]
        })
        var vm = new Vue({
            el: '#app',
            data: {},
            // 挂载路由实例对象
            router: router,
        })
            // 4、创建路由实例对象

    </script>
</body>
9.6 路由重定向

用户再访问 地址 A 的时候,强制用户跳转到地址 C,从而展示特点的组件页面

通过路由规则的 redirect 属性,指定一个新的路由地址,可以很方便的设置路由的定向

        var router = new VueRouter({
            // routes 是路由规则数组
            routes: [
                // 每个路由规则都是一个配置对象,其中至少包括 path 和component 两个属性
                // path 表示当前路由规则匹配的 hash地址
                // component 表示当前路由规则对应要展示的组件,它只接受组件对象,不接受字符串
                
                // '/' 表示需要被重定向的源地址,redirect 表示将要被重定向到的新地址
                { path: '/', redirect: '/user' },
                { path: '/user', component: user },
                { path: '/Register', component: Register },
            ]
        })
9.7 嵌套路由

点击 父级路由链接显示模板内容,模板内容中又有子级路由链接,点击子级路由链接显示子级模板内容

<body>
    <div id="app">
        <!-- 1、添加路由链接 -->
        <router-link to='/user'>User </router-link>
        <router-link to="/Register">Register </router-link>

        <!-- 2、定义路由填充位 -->
        <router-view></router-view>
    </div>
    <script src="./js/vue.js"></script>
    <script src="./js/vue-router.js"></script>
    <script>
        // 3、定义路由组件
        var user = {
            template: ' <h1>user 组件</h1>'
        }
        var Register = {
            template: `
            <div>
                <h1>Register 组件</h1>
                <hr/>
                <router-link to="/Register/tab1">Register/tab1 </router-link>
                <router-link to="/Register/tab2">Register/tab2 </router-link>
                <!-- 子级路由填充位置-->
                <router-view></router-view>
            </div>
            `
        }
        var tab1 = {
            template: '<h3>tab1 子组件</h3>'
        }
        var tab2 = {
            template: '<h3>tab2 子组件</h3>'
        }
        var router = new VueRouter({
            // routes 是路由规则数组
            routes: [
                // 每个路由规则都是一个配置对象,其中至少包括 path 和component 两个属性
                // path 表示当前路由规则匹配的 hash地址
                // component 表示当前路由规则对应要展示的组件,它只接受组件对象,不接受字符串

                // '/' 表示需要被重定向的源地址,redirect 表示将要被重定向到的新地址
                { path: '/', redirect: '/user' },
                { path: '/user', component: user },
                {
                    path: '/Register',
                    component: Register,
                    // children 表示 子路由规则
                    children: [
                        { path: '/Register/tab1', component: tab1 },
                        { path: '/Register/tab2', component: tab2 },
                    ]
                },
            ]
        })
        var vm = new Vue({
            el: '#app',
            data: {},
            // 挂载路由实例对象
            router: router,
        })
            // 4、创建路由实例对象

    </script>
</body>
9.8 动态路由匹配

路由规则,有一部分是一样的,另一部分是动态的、变化的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FmCe7FOa-1620387784183)(vue基础.assets/image-20201026201701456.png)]

<body>
    <div id="app">
        <!-- 1、添加路由链接 -->
        <router-link to='/user/1'>User </router-link>
        <router-link to='/user/2'>User </router-link>
        <router-link to='/user/3'>User </router-link>
        <router-link to="/Register">Register </router-link>

        <!-- 2、定义路由填充位 -->
        <router-view></router-view>
    </div>
    <script src="./js/vue.js"></script>
    <script src="./js/vue-router.js"></script>
    <script>
        // 3、定义路由组件
        var user = {
            template: ' <h1>user 组件--用户id为{{$route.params.id}}</h1>'
        }
        var Register = {
            template: `
            <div>
                <h1>Register 组件</h1>
                <hr/>
            </div>
            `
        }
        var router = new VueRouter({
            // routes 是路由规则数组
            routes: [
                // 每个路由规则都是一个配置对象,其中至少包括 path 和component 两个属性
                // path 表示当前路由规则匹配的 hash地址
                // component 表示当前路由规则对应要展示的组件,它只接受组件对象,不接受字符串

                // '/' 表示需要被重定向的源地址,redirect 表示将要被重定向到的新地址
                { path: '/', redirect: '/user' },
                // :id 表示动态的参数
                { path: '/user/:id', component: user },
                { path: '/Register', component: Register, },
            ]
        })
        var vm = new Vue({
            el: '#app',
            data: {},
            // 挂载路由实例对象
            router: router,
        })
            // 4、创建路由实例对象

    </script>
</body>
9.10 路由组件传递参数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EtR79QkF-1620387784183)(vue基础.assets/image-20201026203125350.png)]

<body>
    <div id="app">
        <!-- 1、添加路由链接 -->
        <router-link to='/user/1'>User </router-link>
        <router-link to='/user/2'>User </router-link>
        <router-link to='/user/3'>User </router-link>
        <router-link to="/Register">Register </router-link>

        <!-- 2、定义路由填充位 -->
        <router-view></router-view>
    </div>
    <script src="./js/vue.js"></script>
    <script src="./js/vue-router.js"></script>
    <script>
        // 3、定义路由组件
        var user = {
            props: ['id'],// 使用props 接收路由参数 
            template: ' <h1>user 组件--用户id为{{id}}</h1>'
        }
        var Register = {
            template: `
            <div>
                <h1>Register 组件</h1>
                <hr/>
            </div>
            `
        }
        var router = new VueRouter({
            // routes 是路由规则数组
            routes: [
                // 每个路由规则都是一个配置对象,其中至少包括 path 和component 两个属性
                // path 表示当前路由规则匹配的 hash地址
                // component 表示当前路由规则对应要展示的组件,它只接受组件对象,不接受字符串
                // '/' 表示需要被重定向的源地址,redirect 表示将要被重定向到的新地址
                { path: '/', redirect: '/user' },
                // :id 表示动态的参数
                // props true 表示 route.params 将会被设置为组件属性
                { path: '/user/:id', component: user, props: true },
                { path: '/Register', component: Register, },
            ]
        })
        var vm = new Vue({
            el: '#app',
            data: {},
            // 挂载路由实例对象
            router: router,
        })
            // 4、创建路由实例对象

    </script>
</body>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kt4mu4bs-1620387784184)(vue基础.assets/image-20201026204401796.png)]

<body>
    <div id="app">
        <!-- 1、添加路由链接 -->
        <router-link to='/user/1'>User </router-link>
        <router-link to='/user/2'>User </router-link>
        <router-link to='/user/3'>User </router-link>
        <router-link to="/Register">Register </router-link>

        <!-- 2、定义路由填充位 -->
        <router-view></router-view>
    </div>
    <script src="./js/vue.js"></script>
    <script src="./js/vue-router.js"></script>
    <script>
        // 3、定义路由组件
        var user = {
            props: ['id', 'uname', 'age'],// 使用props 接收路由参数 
            // 其实这里 是 获取不到 id 的,因为你没有传递过来id
            template: ' <h1>user 组件--用户id为{{id}}--{{uname}}---{{age}}</h1>'
        }
        var Register = {
            template: `
            <div>
                <h1>Register 组件</h1>
                <hr/>
            </div>
            `
        }
        var router = new VueRouter({
            // routes 是路由规则数组
            routes: [
                // 每个路由规则都是一个配置对象,其中至少包括 path 和component 两个属性
                // path 表示当前路由规则匹配的 hash地址
                // component 表示当前路由规则对应要展示的组件,它只接受组件对象,不接受字符串
                // '/' 表示需要被重定向的源地址,redirect 表示将要被重定向到的新地址
                { path: '/', redirect: '/user' },
                // :id 表示动态的参数
                // props true 表示 route.params 将会被设置为组件属性
                { path: '/user/:id', component: user, props: { uname: 'zs', age: 12 } },
                { path: '/Register', component: Register, },
            ]
        })
        var vm = new Vue({
            el: '#app',
            data: {},
            // 挂载路由实例对象
            router: router,
        })
            // 4、创建路由实例对象

    </script>
</body>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NDSRCyXg-1620387784185)(vue基础.assets/image-20201026205729207.png)]

<body>
    <div id="app">
        <!-- 1、添加路由链接 -->
        <router-link to='/user/1'>User </router-link>
        <router-link to='/user/2'>User </router-link>
        <router-link to='/user/3'>User </router-link>
        <router-link to="/Register">Register </router-link>

        <!-- 2、定义路由填充位 -->
        <router-view></router-view>
    </div>
    <script src="./js/vue.js"></script>
    <script src="./js/vue-router.js"></script>
    <script>
        // 3、定义路由组件
        var user = {
            props: ['id', 'uname', 'age'],// 使用props 接收路由参数 
            // 其实这里 是 获取不到 id 的,因为你没有传递过来id
            template: ' <h1>user 组件--用户id为{{id}}--{{uname}}---{{age}}</h1>'
        }
        var Register = {
            template: `
            <div>
                <h1>Register 组件</h1>
                <hr/>
            </div>
            `
        }
        var router = new VueRouter({
            // routes 是路由规则数组
            routes: [
                // 每个路由规则都是一个配置对象,其中至少包括 path 和component 两个属性
                // path 表示当前路由规则匹配的 hash地址
                // component 表示当前路由规则对应要展示的组件,它只接受组件对象,不接受字符串
                // '/' 表示需要被重定向的源地址,redirect 表示将要被重定向到的新地址
                { path: '/', redirect: '/user' },
                // :id 表示动态的参数
                // props true 表示 route.params 将会被设置为组件属性
                {
                    path: '/user/:id',
                    component: user,
                    // route 是一个对象
                    // 箭头函数 左边是 单表达式,要返回一个对象,需要加括号
                    props: route => ({
                        uname: 'zs',
                        age: 20,
                        id: route.params.id
                    })
                },
                { path: '/Register', component: Register, },
            ]
        })
        var vm = new Vue({
            el: '#app',
            data: {},
            // 挂载路由实例对象
            router: router,
        })
            // 4、创建路由实例对象

    </script>
</body>
9.11 命名路由

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0hWcHY1V-1620387784186)(vue基础.assets/image-20201026210546160.png)]

<body>
    <div id="app">
        <!-- 1、添加路由链接 -->
        <router-link to='/user/1'>User </router-link>
        <router-link to='/user/2'>User </router-link>
        <router-link :to="{name:'user',params:{id:3}}">User </router-link>
        <router-link to="/Register">Register </router-link>

        <!-- 2、定义路由填充位 -->
        <router-view></router-view>
    </div>
    <script src="./js/vue.js"></script>
    <script src="./js/vue-router.js"></script>
    <script>
        // 3、定义路由组件
        var user = {
            template: ' <h1>user 组件--用户id为{{$route.params.id}}</h1>'
        }
        var Register = {
            template: `
            <div>
                <h1>Register 组件</h1>
                <hr/>
            </div>
            `
        }
        var router = new VueRouter({
            // routes 是路由规则数组
            routes: [
                { path: '/', redirect: '/user' },
                // :id 表示动态的参数
                // name 起个别名,命名路由
                { path: '/user/:id', component: user, name: 'user' },
                { path: '/Register', component: Register, },
            ]
        })
        var vm = new Vue({
            el: '#app',
            data: {},
            // 挂载路由实例对象
            router: router,
        })
            // 4、创建路由实例对象

    </script>
</body>
9.12 编程式导航

声明式导航:通过点击链接实现导航的方式,比如 a标签,router-link 标签

编程式导航:通过调用 JavaScript 形式的 api 实现导航的方式,如 location.href

常用的编程式导航基本用法

  • this.$router.push(‘hash地址’),表示跳转到这个hash地址
  • this,$router.go(n),正数表示在历史导航中,前进多少部

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aAFAtXoF-1620387784187)(vue基础.assets/image-20201026211712173.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sxugfNqZ-1620387784188)(vue基础.assets/image-20201026212707374.png)]

<body>
    <div id="app">
        <!-- 1、添加路由链接 -->
        <router-link to='/user/1'>User </router-link>
        <router-link to='/user/2'>User </router-link>
        <router-link :to="{name:'user',params:{id:3}}">User </router-link>
        <router-link to="/Register">Register </router-link>

        <!-- 2、定义路由填充位 -->
        <router-view></router-view>
    </div>
    <script src="./js/vue.js"></script>
    <script src="./js/vue-router.js"></script>
    <script>
        // 3、定义路由组件
        var user = {
            template: `
            <div>
                <h1>user 组件--用户id为{{$route.params.id}}</h1>
                <button @click='handle'>跳转到注册页面</button>    
            </div>
            `,
            methods: {
                handle: function () {
                    this.$router.push('/Register')
                }
            }
        }
        var Register = {
            template: `
            <div>
                <h1>Register 组件</h1>
                <hr/>
            </div>
            `
        }
        var router = new VueRouter({
            // routes 是路由规则数组
            routes: [
                { path: '/', redirect: '/user' },
                // :id 表示动态的参数
                // name 起个别名,命名路由
                { path: '/user/:id', component: user, name: 'user' },
                { path: '/Register', component: Register, },
            ]
        })
        var vm = new Vue({
            el: '#app',
            data: {},
            // 挂载路由实例对象
            router: router,
        })
            // 4、创建路由实例对象

    </script>
</body>

10、vue-vouter 案例

10.1 抽离并渲染APP根组件
<body>
    <!-- 要被 vue 实例 所控制的区域 -->
    <div id="app">
        <!-- 路由占位符 -->
        <router-view></router-view>
    </div>

    <script>
        // 定义 根组件 APP
        const App = {
            template: `
            <div>
                <!-- 头部区域 -->
                <header class="header">传智后台管理系统</header>
                <!-- 中间主体区域 -->
                <div class="main">
                    <!-- 左侧菜单栏 -->
                    <div class="content left">
                        <ul>
                            <li>用户管理</li>
                            <li>权限管理</li>
                            <li>商品管理</li>
                            <li>订单管理</li>
                            <li>系统设置</li>
                        </ul>
                    </div>
                    <!-- 右侧内容区域 -->
                    <div class="content right">
                        <div class="main-content">添加用户表单</div>
                    </div>
                </div>
                <!-- 尾部区域 -->
                <footer class="footer">版权信息</footer>
            </div>
            `
        }
        // 创建路由对象
        var router = new VueRouter({
            routes: [
                { path: '/', component: App },
            ]
        })
        var vm = new Vue({
            el: '#app',
            // 将路由挂载到 vm 实例身上
            router,
        })
    </script>
</body>
10.2
<head>
    <meta charset="UTF-8" />
    <title>基于vue-router的案例</title>
    <style type="text/css">
        html,
        body,
        #app {
            margin: 0;
            padding: 0px;
            height: 100%;
        }

        .header {
            height: 50px;
            background-color: #545c64;
            line-height: 50px;
            text-align: center;
            font-size: 24px;
            color: #fff;
        }

        .footer {
            height: 40px;
            line-height: 40px;
            background-color: #888;
            position: absolute;
            bottom: 0;
            width: 100%;
            text-align: center;
            color: #fff;
        }

        .main {
            display: flex;
            position: absolute;
            top: 50px;
            bottom: 40px;
            width: 100%;
        }

        .content {
            flex: 1;
            text-align: center;
            height: 100%;
        }

        .left {
            flex: 0 0 20%;
            background-color: #545c64;
        }

        .left a {
            color: white;
            text-decoration: none;
        }

        .right {
            margin: 5px;
        }

        .btns {
            width: 100%;
            height: 35px;
            line-height: 35px;
            background-color: #f5f5f5;
            text-align: left;
            padding-left: 10px;
            box-sizing: border-box;
        }

        button {
            height: 30px;
            background-color: #ecf5ff;
            border: 1px solid lightskyblue;
            font-size: 12px;
            padding: 0 20px;
        }

        .main-content {
            margin-top: 10px;
        }

        ul {
            margin: 0;
            padding: 0;
            list-style: none;
        }

        ul li {
            height: 45px;
            line-height: 45px;
            background-color: #a0a0a0;
            color: #fff;
            cursor: pointer;
            border-bottom: 1px solid #fff;
        }

        table {
            width: 100%;
            border-collapse: collapse;
        }

        td,
        th {
            border: 1px solid #eee;
            line-height: 35px;
            font-size: 12px;
        }

        th {
            background-color: #ddd;
        }
    </style>
    <script src="./js/vue.js"></script>
    <script src="./js/vue-router.js"></script>
</head>

<body>
    <!-- 要被 vue 实例 所控制的区域 -->
    <div id="app">
        <!-- 路由占位符 -->
        <router-view></router-view>
    </div>

    <script>
        // 定义 根组件 APP
        const App = {

            template: `
            <div>
                <!-- 头部区域 -->
                <header class="header">传智后台管理系统</header>
                <!-- 中间主体区域 -->
                <div class="main">
                    <!-- 左侧菜单栏 -->
                    <div class="content left">
                        <ul>
                            <li><router-link to="/users">用户管理</router-link></li>
                            <li><router-link to="/rigths">权限管理</router-link></li>
                            <li><router-link to="/goods">商品管理</router-link></li>
                            <li><router-link to="/orders">订单管理</router-link></li>
                            <li><router-link to="/settings">系统设置</router-link></li>
                        </ul>
                    </div>
                    <!-- 右侧内容区域 -->
                    <div class="content right">
                        <div class="main-content">
                            <router-view></router-view>
                        </div>
                    </div>
                </div>
                <!-- 尾部区域 -->
                <footer class="footer">版权信息</footer>
            </div>
            `
        }
        var users = {
            data: function () {
                return {
                    userlist: [
                        { id: 1, name: '张三', age: 10 },
                        { id: 2, name: '李四', age: 20 },
                        { id: 3, name: '呆呆狗', age: 30 },
                        { id: 4, name: '张柳', age: 40 },
                    ]
                }
            },

            methods: {
                handle: function (id) {
                    this.$router.push('/userinfo/' + id)
                }
            },
            template: `<div>
            <h3>用户管理区域</h3>
            <table>
                <thead>
                    <tr>
                        <th>编号</th>
                        <th>姓名</th>
                        <th>年龄</th>
                        <th>操作</th>
                    </tr>
                </thead>
                <tbody>
                    <tr v-for="item in userlist"><td>{{item.id}}</td><td>{{item.name}}</td><td>{{item.age}}</td><td><a href="javascript:;" @click='handle(item.id)'>详情</a></td></tr>
                </tbody>
            </table>
            </div>`
        }
        var rigths = { template: `<div><h3>权限管理区域</h3></div>` }
        var goods = { template: `<div><h3>商品管理区域</h3></div>` }
        var orders = { template: `<div><h3>订单管理区域</h3></div>` }
        var settings = { template: `<div><h3>系统设置区域</h3></div>` }
        var userinfo = {
            props: ['id'],
            template: `<div>
                <h5>用户详情页{{id}}</h5>
                <button @click='houtui'>后退</button>
            </div>`,
            methods: {
                houtui: function () {
                    this.$router.go(-1)
                }
            }
        }
        // 创建路由对象
        var router = new VueRouter({
            routes: [
                {
                    path: '/',
                    component: App,
                    children: [
                        { path: '/users', component: users },
                        { path: '/userinfo/:id', component: userinfo, props: true },
                        { path: '/rigths', component: rigths },
                        { path: '/goods', component: goods },
                        { path: '/orders', component: orders },
                        { path: '/settings', component: settings },
                    ],
                    redirect: '/users',
                },
            ]
        })
        var vm = new Vue({
            el: '#app',
            // 将路由挂载到 vm 实例身上
            router,
        })
    </script>
</body>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值