学习 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>
        
        <div>{{msg+'---'+123}}div>
        
    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 指令
  • 解决此问题的原理:先隐藏,替换好值之后再显示最终的值

<html lang="zh-CN">

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

<body>
    <div id="app">
        
        <div v-cloak>{{msg}}div>
        <div v-cloak>{{1+2}}div>
        
        <div v-cloak>{{msg+'---'+123}}div>
        
    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)]


<html lang="zh-CN">

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

<body>
    <div id="app">
        <div>{{msg}}div>
        <div v-text="msg">div>
        
        <div v-html="msg1">div>
        
        <div v-pre>{{msg}}div>
        
    div>
    <script src="./js/vue.js">script>
    <script>

        var vm = new Vue({
            el: '#app',
            data: {
                msg: 'Hello world',
                msg1: '

你好

'
} })
script> body> html>
1.7 数据响应式概念 与 v-once 用法

如何理解响应式

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

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

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

<div v-once>{{msg}}div>

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: '

你好

'
} })
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()'>点击2button>
<body>
    <div id="app">
        <div>{{num}}div>
        <div>
            <button v-on:click='num++'>点击button>
            <button @click='num++'>点击2button>
        div>
        <div>
            <button v-on:click='handle'>点击button>
            <button @click='handle()'>点击2button>
        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)'>点击2button>
            

        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>

<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.14 自定义按键修饰符
<input type="text" @keyup.65='handle'>

<input type="text" @keyup.s='handle'>



<input type="text" v-model="msg" @keyup.aaa="handle">
Vue.config.keyCodes.aaa = 65
// 这个后面的值,代表按键的ASII码,前面的值就是一个名字
// 这样表示只有按 a(65 对应的就是a) 的时候,并且绑定 @keyup.aaa 事件才会触发后面的函数

1.15 简单计算器案例

<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
    <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>
    
    <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>

    <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绑定数组用法

<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
    <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}

<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
    <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}">2222div>
        <div :style="objStyle">2222div>
        <div>数组类型控制stylediv>
        <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-showdiv>
        
    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>

<li :key="item.id" v-for="(item,index) in list">{{item}}+'---'+{{index}}li>
<body>
    <div id="app">
        <ul>
            
            <li v-for='item in fruits'>{{item}}li>
            
            <li v-for='(item,index) in fruits'>{{item}}+'---'+{{index}}li>
             
        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>
            
        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 选项卡

<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
    <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>
                
                
            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>
            
    <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">
                    
                    <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 侦听器案例


<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
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 图书案例源码


<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Documenttitle>
    <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: '    ',
            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: `
{{msg}}
`
} var HelloTom = { data: function () { return { msg: 'hello tom' } }, template: `
{{msg}}
`
} var HelloJerry = { data: function () { return { msg: 'hello Jerry' } }, template: `
{{msg}}
`
} 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:'
{{title}}
'
}) <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: '
{{msg +"---"+title+"-- - "+content}}
'
}) 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:'
{{menuTitle}}
'
})
<body>
    <div id="app">
        
        <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: '
{{msg +"---"+MyTitle}}
'
}) var vm = new Vue({ el: '#app', data: { pmsg: '父组件的内容', ptitle: '动态绑定属性' }, })
script> body>
3.8 父组件向子组件传值 props 属性值类型 必须加:
  • 字符串
  • 数值
  • 布尔值
  • 数组
  • 对象

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

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

<body>
    <div id="app">
        
        <div>{{pmsg}}div>
        
        <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: `
                
{{pstr}}
{{pnum}}
{{pboo}}
  • {{item}}
{{pobj.name}} {{pobj.age}}
`
}) 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: `
            
            `
        })
        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>
        
    div>
    <script src="./js/vue.js">script>
    <script>
        Vue.component('menu-item', {
            template: `
            
            `
            // $emit('第一个参数是事件名称','第二个参数是值') 
        })
        var vm = new Vue({
            el: '#app',
            data: {
                msg: '我是父组件内容',
                fontsize: 14

            },
            methods: {
                handle: function (val) {
                    this.fontsize += val
                }
            }
        })
    script>
body>

    
{{msg}}
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: `
            
TOM:{{num}}
`
, 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: `
JERRY:{{num}}
`
, 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>
        
        
    div>

    <script src="./js/vue.js">script>
    <script>
        Vue.component('test-item', {
            template: `
            
报错 222
`
}) var vm = new Vue({ el: '#app', data: { } })
script> body>
3.13 具名插槽用法
<body>
    <div id="app">
        <test-item>
            <p slot="header">标题信息p>
            <p>主体信息1p>
            <p>主体信息2p>
            <p slot="footer">底部信息p>
        test-item>
        

        
        
        <test-item>
            <template slot="header">
                <p>标题信息1p>
                <p>标题信息2p>
            template>
            <p>主体信息1p>
            <p>主体信息2p>
            <template slot="footer">
                <p>底部信息1p>
                <p>底部信息2p>
            template>
        test-item>
    div>

    <script src="./js/vue.js">script>
    <script>
        Vue.component('test-item', {
            template: `
            
`
}) 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>
                

            template>
        test-item>
    div>

    <script src="./js/vue.js">script>
    <script>
        Vue.component('test-item', {
            props: ['list'],
            template: `
            
  • {{item.name}}
  • `
    }) 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: `
                
    我的商品
    `
    } var CartList = { template: `
    ×
    ×
    ×
    ×
    ×
    `
    } var CartTotal = { template: `
    总价:123
    `
    } Vue.component('my-cart', { template: `
    `
    , 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: `
                
    {{username}}的商品
    `
    } var CartList = { template: `
    ×
    ×
    ×
    ×
    ×
    `
    } var CartTotal = { props: ['list'], // 获取父组件传来的 list 列表 template: `
    总价:{{returnPrice}}
    `
    , 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: `
    `
    , 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: `
                
    {{item.name}}
    ×
    `
    } 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: `
    `
    , 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: `
                
    {{item.name}}
    ×
    `
    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: `
    `
    , 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传递多个参数

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

    
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <title>Documenttitle>
        <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: `
                
    {{username}}的商品
    `
    } 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: `
    {{item.name}}
    ×
    `
    } var CartTotal = { props: ['list'], // 获取父组件传来的 list 列表 template: `
    总价:{{returnPrice}}
    `
    , 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: `
    `
    , 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>
      
      <div id="app">
        
        <a href="#/zhuye">主页a>
        <a href="#/keji">科技a>
        <a href="#/caijing">财经a>
        <a href="#/yule">娱乐a>
        
        
        <component :is="comName">component>
      div>
    
      <script>
        // 主页组件
        const zhuye = {
          template: '

    主页信息

    '
    } // 科技组件 const keji = { template: '

    科技信息

    '
    } // 财经组件 const caijing = { template: '

    财经信息

    '
    } // 娱乐组件 const yule = { template: '

    娱乐信息

    '
    } 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">
            
            <router-link to='/user'>User router-link>
            <router-link to="/Register">Register router-link>
    
            
            <router-view>router-view>
        div>
        <script src="./js/vue.js">script>
        <script src="./js/vue-router.js">script>
        <script>
            // 3、定义路由组件
            var user = {
                template: ' 

    user 组件

    '
    } var Register = { template: '

    Register 组件

    '
    } 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">
            
            <router-link to='/user'>User router-link>
            <router-link to="/Register">Register router-link>
    
            
            <router-view>router-view>
        div>
        <script src="./js/vue.js">script>
        <script src="./js/vue-router.js">script>
        <script>
            // 3、定义路由组件
            var user = {
                template: ' 

    user 组件

    '
    } var Register = { template: `

    Register 组件


    Register/tab1 Register/tab2
    `
    } var tab1 = { template: '

    tab1 子组件

    '
    } var tab2 = { template: '

    tab2 子组件

    '
    } 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">
            
            <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>
    
            
            <router-view>router-view>
        div>
        <script src="./js/vue.js">script>
        <script src="./js/vue-router.js">script>
        <script>
            // 3、定义路由组件
            var user = {
                template: ' 

    user 组件--用户id为{{$route.params.id}}

    '
    } var Register = { template: `

    Register 组件


    `
    } 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">
            
            <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>
    
            
            <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: ' 

    user 组件--用户id为{{id}}

    '
    } var Register = { template: `

    Register 组件


    `
    } 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">
            
            <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>
    
            
            <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: ' 

    user 组件--用户id为{{id}}--{{uname}}---{{age}}

    '
    } var Register = { template: `

    Register 组件


    `
    } 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">
            
            <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>
    
            
            <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: ' 

    user 组件--用户id为{{id}}--{{uname}}---{{age}}

    '
    } var Register = { template: `

    Register 组件


    `
    } 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">
            
            <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>
    
            
            <router-view>router-view>
        div>
        <script src="./js/vue.js">script>
        <script src="./js/vue-router.js">script>
        <script>
            // 3、定义路由组件
            var user = {
                template: ' 

    user 组件--用户id为{{$route.params.id}}

    '
    } var Register = { template: `

    Register 组件


    `
    } 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">
            
            <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>
    
            
            <router-view>router-view>
        div>
        <script src="./js/vue.js">script>
        <script src="./js/vue-router.js">script>
        <script>
            // 3、定义路由组件
            var user = {
                template: `
                

    user 组件--用户id为{{$route.params.id}}

    `
    , methods: { handle: function () { this.$router.push('/Register') } } } var Register = { template: `

    Register 组件


    `
    } 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>
        
        <div id="app">
            
            <router-view>router-view>
        div>
    
        <script>
            // 定义 根组件 APP
            const App = {
                template: `
                
    传智后台管理系统
    • 用户管理
    • 权限管理
    • 商品管理
    • 订单管理
    • 系统设置
    添加用户表单
    版权信息
    `
    } // 创建路由对象 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>
        
        <div id="app">
            
            <router-view>router-view>
        div>
    
        <script>
            // 定义 根组件 APP
            const App = {
    
                template: `
                
    传智后台管理系统
    • 用户管理
    • 权限管理
    • 商品管理
    • 订单管理
    • 系统设置
    版权信息
    `
    } 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: `

    用户管理区域

    编号 姓名 年龄 操作
    {{item.id}}{{item.name}}{{item.age}}详情
    `
    } var rigths = { template: `

    权限管理区域

    `
    } var goods = { template: `

    商品管理区域

    `
    } var orders = { template: `

    订单管理区域

    `
    } var settings = { template: `

    系统设置区域

    `
    } var userinfo = { props: ['id'], template: `
    用户详情页{{id}}
    `
    , 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>

    你可能感兴趣的:(前端学习笔记,vue,vue)