【4.0】Vue之指令系统

发布时间 2023-08-06 22:33:31作者: Chimengmeng

【一】指令系统之文本指令(v-text/v-html)

  • 写在标签上,v-开头的 标签,称之为指令,每个指令都有特殊用途
  • v-指令名='写原来插值能写的东西'
  • v-指令名='name' # 变量
  • v-text
    • v-text 指令用于将变量的值渲染到标签的内部。
    • 它会将变量的值作为纯文本内容输出到标签之间,而不会将值作为 HTML 解析。
    • 这意味着如果变量的值包含 HTML 标签,它们将会被转义显示,而不会成为实际的标签。
  • v-html
    • v-html 指令用于将标签类型的字符串直接渲染成标签。
    • 它会取变量的值并将其作为有效的 HTML 解析和渲染,即使字符串中含有 HTML 标签也会正确解析并显示为相应的标签结构。
    • 这个指令主要适用于在变量中包含了富文本内容或者需要动态生成的标签。
  • 这两种指令可以通过 Vue.js 的数据绑定功能在模板中使用,以实现根据变量的值来动态改变标签的内容。
    • 其中,v-text 是一种更安全的做法,它可以避免潜在的 XSS(跨站脚本)攻击,因为它会将变量值作为纯文本输出。
    • 而 v-html 则需要谨慎使用,应确保要渲染的内容是可信的,避免恶意代码注入。
  • v-if
    • 只能写条件或布尔类型的变量,用于判断是否显示DOM元素。
    • 当条件为true时,该DOM元素会被渲染到页面上;
    • 当条件为false时,该DOM元素会被完全删除,即不会有任何渲染和存在的痕迹。
  • v-show
    • 同样只能写条件或布尔类型的变量,用于判断是否显示DOM元素。
    • 当条件为true时,该DOM元素会以正常的方式显示在页面上;
    • 当条件为false时,该DOM元素的CSS属性会被设置为 display:none,从而使其在页面上不可见。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <!-- 引入 Vue.js 文件 -->
    <script src="vue2.js"></script>
    <!-- 如果需要使用CDN引入Vue.js库,请取消注释下面一行代码,并注释上面一行代码 -->
    <!--     <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.7.9/vue.min.js"></script>-->
</head>
<body>
<div id="app">
    <!--  (1) 文本指令之 v-text ,将变量渲染到标签内部 -->
    <span v-text="a_div"></span>
    <br>
    <!--  (1) 文本指令之 v-html ,将标签类型的字符串直接渲染成标签 -->
    <span v-html="a_div"></span>
    <h2>v-if的使用,只能写条件或布尔类型的变量,为false时,完全删除标签</h2>
    <div v-if="is_show">
        这是第一个div标签
    </div>
    <div v-if="is_hide">
        这是第二个个div标签
    </div>
    <br>
    <h2>v-show的使用,只能写条件或布尔类型的变量,为false时,将标签的属性设置为 display:none</h2>
    <div v-show="is_show">
        这是第三个div标签
    </div>
    <div v-show="is_hide">
        这是第四个div标签
    </div>
    <br>

</div>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            a_div: '<a href="https://www.baidu.com/">点我了解更多</a>',
            is_show: true,
            is_hide: false,
        }
    })
</script>
</body>
</html>

【二】指令系统之事件指令(v-on)

  • 点击事件:
    • 可以通过指令系统给某个标签绑定一个点击事件。当用户点击该标签时,就会执行相应的函数。
    • 在Vue.js中,可以使用v-on指令来实现这一功能。
  • v-on指令:
    • v-on指令用于监听DOM事件,并在事件触发时执行相应的函数。
    • 语法格式为:v-on:事件名="函数名"。
    • 其中,事件名可以是DOM事件名称,如click、mouseover等。
  • 重点:
    • @简写形式:Vue.js还提供了一种简写形式来使用v-on指令,即通过在标签上使用@事件="函数名"的方式来绑定事件。
    • 例如,@click="handleClick"表示当用户点击该标签时,会执行名为handleClick的函数。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <!-- 引入 Vue.js 文件 -->
    <script src="vue2.js"></script>
    <!-- 如果需要使用CDN引入Vue.js库,请取消注释下面一行代码,并注释上面一行代码 -->
    <!--     <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.7.9/vue.min.js"></script>-->
</head>
<body>
<div id="app">
    <!--  事件指令 -->
    <button v-on:click="handleClick1">点我有美女</button>
    <br>
    <button v-on:click="handleClick2">点我有帅哥</button>
    <br>
    <!--  简写形式:@事件="函数名" -->
    <button @click="handleClick3">点我看真美女!</button>
    <br>
    <div v-show="is_show">
        <img src="https://tse4-mm.cn.bing.net/th/id/OIP-C.0IofWmapl7nz3v31JQm8dQHaNK?pid=ImgDet&rs=1" alt="">
    </div>
</div>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            is_show: true,
        }, // data 内放的都是变量/数据
        methods: {
            "handleClick1": function () {
                alert('看美女')
            },
            // "handleClick2": function () {
            //     alert('看帅哥')
            // }
            // 简写
            handleClick2() {
                alert('看帅哥')
            },

            handleClick3() {
                // data中定义的变量,都可以通过this取到
                this.is_show = !this.is_show
            }
        }
    })

    // es6的简写形式
    var a = {"name": "dream", "age": 19}
    var b = {name: "dream", age: 19} // 一次简写
    var name = "dream"
    var age = 19
    var f = function () {
    }
    var d = {
        "name": name, "age": age, "f": function () {
        }
    } // 二次简写
    var e = {name, age, f} // 三次简写 ---> {"name": name, "age": age,f:function () {}}
</script>
</body>
</html>
  • 在Vue中,可以使用@click指令来绑定点击事件,并且可以传递参数。
    • 在模板中使用@click时,可以在双引号或单引号内部传递实参。
<body>
<div id="app">
    <!--  实参  -->
    <h1>函数。可以多传参数,也可以少传参数,都不会报错</h1>
    <button @click="handelClick1('dream',18)">点我</button>
    <br>
    <h1>事件对象,调用函数,不传参数,会把当前event事件对象传入,可以不接收也可以接收</h1>
    <button @click="handelClick2">点我</button>
    <br>
    <h2>主动将实参和event事件传入进去,使用$event 方法,不传这个参数会提示undefined</h2>
    <button @click="handelClick3('dream',$event)">点我</button>
    <br>


</div>
</body>

<script>
    var vm = new Vue({
        el: "#app",
        data: {},
        methods: {
            // 形参用来接收实参
            handelClick1(name, age) {
                console.log(name, age) // dream 18
            },
            handelClick2(event) {
                console.log(event) // PointerEvent {isTrusted: true, pointerId: 1, width: 1, height: 1, pressure: 0, …}
            },
            handelClick3(name, event) {
                console.log(name) // dream
                console.log(event) // PointerEvent {isTrusted: true, pointerId: 1, width: 1, height: 1, pressure: 0, …}
            },
        },
    })
</script>
  • [1]使用双引号或单引号直接传递参数:
html<button @click="handelClick1('dream',18)">点我</button>
  • 当按钮被点击时,会调用handelClick1方法并传递两个实参,即字符串'dream'和数字18。
    • handelClick1方法中的形参nameage分别接收了这两个实参。
  • [2]不传递参数,自动传入事件对象参数:
html<button @click="handelClick2">点我</button>
  • 当按钮被点击时,会调用handelClick2方法,此时没有传递任何实参。
    • 但是在Vue中,当你不传递任何参数时,会自动将事件对象作为默认参数传入到对应的方法中。
    • 因此,在handelClick2方法中,通过形参event接收了当前的事件对象。
  • [3]主动传入事件对象参数:
<button @click="handelClick3('dream',$event)">点我</button>
  • 当按钮被点击时,会调用handelClick3方法,并传递了两个实参,一个是字符串'dream',另一个是特殊的$event对象。
    • $event是Vue为我们提供的特殊变量,它代表当前事件对象。
    • handelClick3方法中,通过形参name接收了字符串'dream',而通过形参event接收了事件对象。

【三】指令系统之属性指令(v-bind)

【1】引入(url)

  • 属性指令是Vue.js框架中的一种指令,用于动态地绑定HTML元素的属性值。

    • 通过属性指令,我们可以将特定的Vue实例中的数据绑定到HTML元素的属性上,并实现属性值的动态更新。
  • 每个标签都有各自的属性

    • 比如nameidclasssrchref ...

    • 在以前的写法中,name=xx这样写就等于把name属性写死,而我们现在想动态的绑定变量,变量变化,属性值也发生变化

  • 语法

    • v-bind:属性名='变量'
    • 其中属性名是HTML元素的属性名称,变量是Vue实例中的一个数据。
  • 简写

    • :属性名='变量'
<body>
<div id="app">
    <h1>属性指令</h1>
    <button @click="clickFunction">点我有惊喜</button>
    <br>
    <img v-bind:src="url" alt="" style="height: 100px;width: auto">

</div>
</body>

<script>
    var vm = new Vue({
        el: "#app",
        data: {
            url: 'https://img0.baidu.com/it/u=2911164322,2998857390&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1691082000&t=332668429a69761c46e219f3c9e42e6e',
        },
        methods: {
            clickFunction() {
                this.url = 'https://img0.baidu.com/it/u=1283150498,416567485&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1691082000&t=c7e955ff3a2f8d0e642040536b5d9002'
            }
        }

    })
</script>
  • 随机切换美女图片
    • 每隔一段时间切换美女图片
    • 点击美女图片停止切换
    • 定时器的设置与移除
</body>

<script>
    var vm = new Vue({
        el: "#app",
        data: {
            url: 'https://img0.baidu.com/it/u=2911164322,2998857390&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1691082000&t=332668429a69761c46e219f3c9e42e6e',
            // 美女图片链接数组
            url_list: [
                'https://img0.baidu.com/it/u=3794430030,3426009381&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=750',
                'https://img2.baidu.com/it/u=1229150163,1065025162&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=1163',
                'https://img0.baidu.com/it/u=47162254,1618159860&fm=253&fmt=auto&app=120&f=JPEG?w=1422&h=800',
                'https://img1.baidu.com/it/u=2330322620,1600682306&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500',
                'https://img0.baidu.com/it/u=1014602630,2478090858&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500',
                'https://img1.baidu.com/it/u=1467066664,2486063241&fm=253&fmt=auto&app=120&f=JPEG?w=1280&h=800',
                'https://img2.baidu.com/it/u=2536923080,486325759&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500',
            ],
            inter: null,
        },
        methods: {
            clickStart() {
                // 定时器:每隔一段时间执行某个方法
                // 先将 this 对象存起来,在下面的函数中 this的指向发生了变化
                var _this = this;
                this.inter = setInterval(function () {
                    // 随机从列表中取值赋值
                    // Math.floor : 向下取整数
                    // Math.random() : 随机生成 0-1 之间的小数
                    // this.url_list.length : 图片链接列表的长度
                    var num = Math.floor(Math.random() * _this.url_list.length)
                    _this.url = _this.url_list[num]
                }, 1000) // 每隔1000ms执行一次定时器的函数
            },
            clickEnd() {
                // 停止定时器 ----- 移除定时器
                clearInterval(this.inter);
                this.inter = null;
            },
            clickStop() {
                // 停止定时器 ----- 移除定时器
                clearInterval(this.inter);
                this.inter = null;

            },
        }

    })
</script>

【2】class

  • style和class也是属性,可以使用属性指令

    • :class :style
  • 但是style和class比较特殊

<body>
<div id="app">
    <h1>class属性:可以是文本/数组/对象</h1>
    <div :class="class_str">
        这是一个文本div标签
    </div>
    <br>
    <div :class="class_tup">
        这是一个数组div标签
    </div>
    <br>
    <div :class="class_cls">
        这是一个对象div标签
    </div>
    <br>
    <div :class="class_back">
        这是一个响应式对象div标签
    </div>
    <br>
    <div>
        <button @click="clickChangeStr">点我切换文本样式</button>
        <button @click="clickChangeTup">点我数组文本样式</button>
        <button @click="clickChangeCls">点我切换对象样式</button>
        <button @click="clickChangeBack">点我切换响应式对象样式</button>
    </div>

</div>
</body>

<script>
    var vm = new Vue({
        el: "#app",
        data: {
            style_list: ['size', 'yellow', 'red', 'green'],

            // *************************class开始**************************
            // class 推荐使用数组形式

            // class 绑定的变量,变量可以是字符串
            class_str: 'size red',
            // class 绑定的变量,变量可以是数组
            class_tup: ['yellow', 'size'],
            // class 绑定的变量,变量可以是对象 . 如果是对象,需要提前将属性值设置上,然后通过改变 true/false 控制属性的显示,如果向其中添加不存在的值就不会显示效果
            // 新添加的值不会被监听,所以不会有响应式
            class_cls: {size: true, red: true, yellow: false, green: false},
            class_back: {size: true},
            // *************************class结束**************************
        },
        methods: {
            // *************************class开始**************************
            clickChangeStr() {
                this.class_str = this.style_list[Math.floor(Math.random() * this.style_list.length)];

            },
            clickChangeTup() {
                if (this.class_tup.length >= 3) {
                    this.class_tup = [];
                } else {
                    // 给 class_tup 追加值 ,class_tup 会发生变化,页面也会发生变化 vm.class_tup.push('属性值')
                    vm.class_tup.push(this.style_list[Math.floor(Math.random() * this.style_list.length)]);
                }
            },
            clickChangeCls() {

            },
            clickChangeBack() {
                // this.class_back.yellow = true // 对象中没有提前定义,后面添加值不会被监听(不产生响应式)
                // Vue.set(数据对象, key, value);
                Vue.set(this.class_back, 'yellow', true);
            },
            // *************************class结束**************************
        }

    })
</script>

【3】style

<body>
<div id="app">
    <h1>style属性:可以是文本/数组/对象</h1>
    <div :style="style_str">
        这是一个文本div标签
    </div>
    <br>
    <div :style="style_tup">
        这是一个数组div标签
    </div>
    <br>
    <div :style="style_cls">
        这是一个对象div标签
    </div>
    <br>
    <div :style="style_back">
        这是一个响应式对象div标签
    </div>
    <br>
    <div>
        <button @click="clickChangeStrStyle">点我切换文本样式</button>
        <button @click="clickChangeTupStyle">点我数组文本样式</button>
        <button @click="clickChangeClsStyle">点我切换对象样式</button>
        <button @click="clickChangeBackStyle">点我切换响应式对象样式</button>
    </div>


</div>
</body>

<script>
    var vm = new Vue({
        el: "#app",
        data: {
            style_list: ['size', 'yellow', 'red', 'green'],

            // *************************style开始**************************
            // style  推荐使用  对象形式

            // style 绑定的变量,变量可以是字符串
            style_str: 'font-size: 38px;background-color: yellow',
            // style 绑定的变量,变量可以是数组
            style_tup: [{'font-size': '66px'}],
            // style 绑定的变量,变量可以是对象 . 如果是对象,需要提前将属性值设置上,然后通过改变 true/false 控制属性的显示,如果向其中添加不存在的值就不会显示效果
            // 新添加的值不会被监听,所以不会有响应式
            style_cls: {'font-size': '66px', 'background-color': 'red'},
            // 对象形式 省略引号格式变为 驼峰形式
            // style_cls: {fontSize: '66px', backgroundColor: 'red'},
            style_back: {'font-size': '66px'}
            // *************************style结束**************************
        },
        methods: {
            // *************************style开始**************************
            clickChangeStrStyle() {
                this.style_str = 'background-color: red'

            },
            clickChangeTupStyle() {
                if (this.style_tup.length >= 3) {
                    this.style_tup = [];
                } else {
                    // 给 class_tup 追加值 ,class_tup 会发生变化,页面也会发生变化 vm.class_tup.push('属性值')
                    vm.style_tup.push({'background-color': 'red'});
                }
            },
            clickChangeClsStyle() {

            },
            clickChangeBackStyle() {
                // this.class_back.yellow = true // 对象中没有提前定义,后面添加值不会被监听(不产生响应式)
                // Vue.set(数据对象, key, value);
                Vue.set(this.style_back, 'background-color', 'red');
            },
            // *************************style结束**************************
        }

    })
</script>

【四】指令系统之条件渲染(v-if)

  • v-if v-else-if v-else

  • 根据学生分数显示学生的水平

<body>
<div id="app">
    <h1>条件渲染 v-if v-else-if v-else</h1>

    <div v-if="score>90&&score<=100">优秀</div>
    <div v-else-if="score>70&&score<=90">良好</div>
    <div v-else-if="score>60&&score<=70">及格</div>
    <div v-else>不及格</div>

</div>
</body>

<script>
    var vm = new Vue({
        el: "#app",
        data: {
            score: 55,
        },
        methods: {}
    })
</script>

【五】指令系统之列表渲染(v-for)

  • 循环渲染数据

    • 比如购物车的数据
  • v-for

    • 循环字符串、数组、数字、对象

【1】v-for 循环数组类型

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <script src="vue.min.js"></script>
    <!--  jQuery 文件  -->
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.0/jquery.min.js">//jQuery</script>
    <!--  Bootstrap 的 CSS 样式文件  -->
    <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css">
    <!--  Bootstrap 的 JS 文件 (动画效果需要jQuery)  -->
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js">// bootstrap </script>
    <!--  Vue 文件  -->
    <!--        <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.7.9/vue.min.js"></script>-->
    <!--  以下为 css样式书写区  -->
    <style>

    </style>

</head>
<body>
<div id="app">

    <div class="container-fluid">
        <div class="row">
            <div class="col-md-6 col-md-offset-3">
                <h1 class="text-center">列表渲染 v-for</h1>
                <div class="pull-right">
                    <button class="btn btn-danger" @click="handleClick">加载购物车</button>
                </div>
                <table class="table table-hover">
                    <thead>
                    <tr>
                        <th class="text-center">id</th>
                        <th class="text-center">商品名称</th>
                        <th class="text-center">商品库存</th>
                        <th class="text-center">商品价格</th>
                    </tr>
                    </thead>
                    <tbody>
                    <tr v-for="good in good_list">
                        <th scope="row" class="text-center">{{good.id}}</th>
                        <td class="text-center">{{good.name}}</td>
                        <td class="text-center">{{good.stock}}</td>
                        <td class="text-center">{{good.price}}</td>
                    </tr>
                    </tbody>
                </table>
            </div>
        </div>
    </div>
</div>
</body>

<script>
    var vm = new Vue({
        el: "#app",
        data: {
            good_list: []
        },
        methods: {
            handleClick() {
                this.good_list = [
                    {'id': 1, 'name': '小汽车', 'stock': 3, 'price': 66666},
                    {'id': 2, 'name': '小飞机', 'stock': 5, 'price': 55555},
                    {'id': 3, 'name': '小火车', 'stock': 78, 'price': 88888},
                    {'id': 4, 'name': '小游轮', 'stock': 976, 'price': 77777},
                    {'id': 5, 'name': '小潜艇', 'stock': 786, 'price': 33333},
                    {'id': 6, 'name': '小导弹', 'stock': 56, 'price': 22222},
                    {'id': 7, 'name': '小趴菜', 'stock': 36, 'price': 999999},
                ]
            },
        }
    })
</script>

</html>

【2】v-for 循环其他类型

  • 循环对象时
    • 需要注意将"value"放在前面,"key"放在后面。
    • 这是因为Vue.js中的v-for指令默认是以"(value, key, index)"的形式来遍历对象的每一项。
  • v-for指令也支持循环时使用索引值
    • 可以在循环体中通过"$index"来访问当前项的索引值
  • 有时候别人的代码会带一个 key 属性
    • 目的是为了提高虚拟 dom 的替换效率
    • <el-carousel-item v-for='item in 4 ' :key='item'>
    • key 的值必须唯一,不唯一就会报错
  • 如果设置数据发生了变化,而页面没有发生变化,可以使用Vue.set方法
    • Vue.set(对象,key,value)
    • Vue.set(数据,索引,值)
    • 使用Vue.set方法来触发响应式更新。
    • Vue.set方法接收三个参数,分别是对象、key和value。
    • 如果你是针对数组进行修改,可以将索引作为第二个参数,然后再传入需要修改的值。这样就能保证页面根据数据的变化进行更新。
<body>
<div id="app">

    <div class="container-fluid">
        <div class="row">
            <div class="col-md-6 col-md-offset-3">


                <table class="table table-hover">
                    <thead>

                    </thead>
                    <tbody>
                    <!--       循环数字             -->
                    <h1 class="text-center">列表渲染 v-for 循环数字</h1>
                    <ul class="list-unstyled">
                        <li v-for="(index,num) in number" class="text-center ">{{index}} {{num}}</li>
                    </ul>
                    <!--       循环字符串            -->
                    <h1 class="text-center">列表渲染 v-for 循环字符串</h1>
                    <ul class="list-unstyled">
                        <li v-for="str in strs" class="text-center ">{{str}}</li>
                    </ul>
                    <h1 class="text-center">列表渲染 v-for 循环数组</h1>
                    <ul class="list-unstyled">
                        <li v-for="tup in tups" class="text-center ">{{tup}}</li>
                    </ul>
                    <h1 class="text-center">列表渲染 v-for 循环对象</h1>
                    <ul class="list-unstyled">
                        <li v-for="(value,key) in clss" class="text-center ">
                            key::{{key}}
                            value::{{value}}
                        </li>
                    </ul>

                    </tbody>
                </table>
            </div>
        </div>
    </div>
</div>
</body>

<script>
    var vm = new Vue({
        el: "#app",
        data: {
            number: 10,
            strs: "dream",
            tups: ["dream", 5, 9, 8, 7, 6, 8],
            clss:  {'id': 1, 'name': '小汽车', 'stock': 3, 'price': 66666}
        },
        methods: {}
    })
</script>

【六】指令系统之数据双向绑定(v-model)

【1】基础

  • 数据双向绑定只有 input 标签
    • v-model 做双向数据绑定
<body>
<div id="app">
    <p>用户名<input type="text" class="form-control" v-model="username"></p>
    <p>密码<input type="password" class="form-control" v-model="password"></p>
    <p>
        <button class="btn btn-success" @click="clickFunction">登陆</button>
    </p>

</div>
</body>

<script>
    var vm = new Vue({
        el: "#app",
        data: {
            username: '',
            password: '',
        },
        methods: {
            clickFunction() {
                console.log(this.username)
                console.log(this.password)
            }
        }
    })
</script>

【2】进阶(lazy/number/trim)

  • lazy:
    • 等待input框的数据绑定时区焦点之后再变化
  • number:
    • 数字开头,只保留数字,后面的字母不保留;
    • 字母开头,都保留
  • trim:
    • 去除首位的空格
<body>
<div id="app">
    <h1>v-model进阶</h1>
    <h2>内容随输入变化而变化</h2>
    <input type="text" v-model="username"> username数据----->{{username}}
    <br>
    <h2>lazy修饰:内容随鼠标失去焦点而变化,节省效率</h2>
    <input type="text" v-model.lazy="username1"> username数据----->{{username1}}
    <br>
    <h2>number修饰:数字开头,只保留数字,后面的字母不保留;字母开头,都保留</h2>
    <input type="text" v-model.number="username2"> username数据----->{{username2}}
    <br>
    <h2>trim修饰:去除首位的空格</h2>
    <input type="text" v-model.trim="username3"> username数据----->{{username3}}

</div>
</body>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            username: '',
            username1: '',
            username2: '',
            username3: '',
        },
        methods: {}
    })
</script>

【七】指令系统之事件处理

  • 事件指令
    • click点击事件
  • input标签的事件
    • input
      • 只要输入内容,就会触发
    • change
      • 只要输入框发生变化,就会触发
    • blur
      • 只要失去焦点,就会触发
<div id="app">
    <h1>input事件</h1>
    <input type="text" @input="inputFunction" v-model="username"> username ----> {{username}}
    <h1>change事件</h1>
    <input type="text" @change="changeFunctionC" v-model="content"> username ----> {{content}}
    <h1>blur事件</h1>
    <input type="text" @blur="blurFunctionC" v-model="detail"> username ----> {{detail}}
</div>
</body>

<script>
    var vm = new Vue({
        el: "#app",
        data: {
            username: '',
            content: '',
            detail: '',
        },
        methods: {
            inputFunction() {
                console.log(this.username)
            },
            changeFunctionC() {
                console.log(this.content)
            },
            blurFunctionC() {
                console.log("已经失去焦点")
                console.log(this.detail)
            },
        }
    })
</script>

【八】指令系统案例之过滤案例

<body>
<div id="app">
    <h1>过滤案例</h1>
    <input type="text" v-model="search" @input="inputFunc"> {{search}}
    <br>
    <ul class="list-unstyled">
        <li v-for="item in new_datalist">{{item}}</li>
    </ul>
</div>
</body>

<script>
    var vm = new Vue({
        el: "#app",
        data: {
            search: '',
            datalist: ['a', 'ab', 'cb', 'ww', '5e', '7k7k'],
            new_datalist: ['a', 'ab', 'cb', 'ww', '5e', '7k7k']

        },
        methods: {
            // inputFunc() {
            //     console.log(this.search)
            //     // 根据用户输入的 search ,对数组进行过滤,剩下质保函输入文字的字符串
            //     var _this = this
            //     this.new_datalist = this.datalist.filter(function (item) {
            //         if (item.indexOf(_this.search) >= 0) {
            //             return true
            //         } else {
            //             return false
            //         }
            //     })
            // }

            // 优化 --- 直接返回结果
            // inputFunc() {
            //     console.log(this.search)
            //     // 根据用户输入的 search ,对数组进行过滤,剩下质保函输入文字的字符串
            //     var _this = this
            //     this.new_datalist = this.datalist.filter(function (item) {
            //         return (item.indexOf(_this.search) >= 0)
            //     })
            // }

            // 三次优化  --- 箭头函数
            inputFunc() {
                this.new_datalist = this.datalist.filter(item => item.indexOf(this.search) >= 0)
            }

        }
    })


</script>

【九】指令系统之表单控制

  • checkbox
    • 单选
    • 多选
  • radio
    • 单选
<body>
<div id="app">
    <h1>表单控制</h1>
    <br>
    <h1>checkbox单选</h1>
    <p>用户名::<input type="text" v-model="username"></p>
    <p>密码::<input type="password" v-model="password"></p>
    <p>记住密码::<input type="checkbox" v-model="remember"></p>
    <br>
    用户名: {{username}}
    <br>
    密码: {{password}}
    <br>
    记住密码: {{remember}}
    <br>

    <h1>checkbox多选</h1>
    <p>用户名::<input type="text" v-model="username"></p>
    <p>密码::<input type="password" v-model="password"></p>
    <p>爱好::
        篮球:>>><input type="checkbox" v-model="hobby" value="篮球">
        足球:>>><input type="checkbox" v-model="hobby" value="足球">
        排球:>>><input type="checkbox" v-model="hobby" value="排球">
    </p>
    <br>
    用户名: {{username}}
    <br>
    密码: {{password}}
    <br>
    爱好: {{hobby}}
    <br>

    <h1>radio单选</h1>
    <p>用户名::<input type="text" v-model="username"></p>
    <p>密码::<input type="password" v-model="password"></p>
    <p>爱好::
        篮球:>>><input type="checkbox" v-model="hobby" value="篮球">
        足球:>>><input type="checkbox" v-model="hobby" value="足球">
        排球:>>><input type="checkbox" v-model="hobby" value="排球">
    </p>
    <p>性别::
        男::<input type="radio" v-model="gender" value="男">
        女::<input type="radio" v-model="gender" value="女">
        保密::<input type="radio" v-model="gender" value="保密">
    </p>
    <br>
    用户名: {{username}}
    <br>
    密码: {{password}}
    <br>
    爱好: {{hobby}}
    <br>
    性别: {{gender}}
    <br>

</div>
</body>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            username: '',
            password: '',
            remember: false, // 默认不被选中
            hobby: [],
            gender: '',
        },
        methods: {}
    })
</script>

【十】指令系统案例之购物车案例

  • 选中商品
    • 自动计算总价 数量 * 价格
<body>
<div id="app">

    <div class="container-fluid">
        <div class="row">
            <div class="col-md-6 col-md-offset-3">
                <h1 class="text-center">购物车</h1>
                <hr>
                <table class="table table-hover">
                    <thead>
                    <tr>
                        <th class="text-center">商品ID</th>
                        <th class="text-center">商品名称</th>
                        <th class="text-center">商品库存</th>
                        <th class="text-center">商品价格</th>
                        <th class="text-center">操作</th>
                    </tr>
                    </thead>
                    <tbody>
                    <tr v-for="good in good_list">
                        <th scope="row" class="text-center">{{good.id}}</th>
                        <td class="text-center">{{good.name}}</td>
                        <td class="text-center">{{good.stock}}</td>
                        <td class="text-center">{{good.price}}</td>
                        <td class="text-center"><input type="checkbox" :value="good" v-model="check_group"></td>
                    </tr>
                    </tbody>
                </table>
                <hr>
                <h3>选中商品::{{check_group}}</h3>
                <h3>总价格::{{sumPrice()}}</h3>
                <h3>选中了checkbox,check_group会发生变化,页面也在变,都会重新刷新页面,函数就会重新执行</h3>
            </div>
        </div>
    </div>


</div>
</body>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            good_list: [
                {'id': 1, 'name': '小汽车', 'stock': 3, 'price': 66666},
                {'id': 2, 'name': '小飞机', 'stock': 5, 'price': 55555},
                {'id': 3, 'name': '小火车', 'stock': 78, 'price': 88888},
                {'id': 4, 'name': '小游轮', 'stock': 976, 'price': 77777},
                {'id': 5, 'name': '小潜艇', 'stock': 786, 'price': 33333},
                {'id': 6, 'name': '小导弹', 'stock': 56, 'price': 22222},
                {'id': 7, 'name': '小趴菜', 'stock': 36, 'price': 999999},
            ],
            check_group: []
        },
        methods: {
            sumPrice() {
                // 计算总价格  根据 check_group 内的数据
                // check_group 循环取出价格和数量
                var total = 0;
                for (item of this.check_group) {
                    total += item.stock * item.price
                }
                return total
            }
        }
    })
</script>
  • 全选
<body>
<div id="app">

    <div class="container-fluid">
        <div class="row">
            <div class="col-md-6 col-md-offset-3">
                <h1 class="text-center">购物车</h1>
                <hr>
                <table class="table table-hover">
                    <thead>
                    <tr>
                        <th class="text-center">商品ID</th>
                        <th class="text-center">商品名称</th>
                        <th class="text-center">商品库存</th>
                        <th class="text-center">商品价格</th>
                        <th class="text-center">选中全部 <input type="checkbox" v-model="checkAll" @change="selectALL">
                        </th>
                    </tr>
                    </thead>
                    <tbody>
                    <tr v-for="good in good_list">
                        <th scope="row" class="text-center">{{good.id}}</th>
                        <td class="text-center">{{good.name}}</td>
                        <td class="text-center">{{good.stock}}</td>
                        <td class="text-center">{{good.price}}</td>
                        <td class="text-center"><input type="checkbox" :value="good" v-model="check_group"
                                                       @change="selectOne"></td>
                    </tr>
                    </tbody>
                </table>
                <hr>
                <h3>全选::{{checkAll}}</h3>
                <h3>选中商品::{{check_group}}</h3>
                <h3>总价格::{{sumPrice()}}</h3>
            </div>
        </div>
    </div>


</div>
</body>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            good_list: [
                {'id': 1, 'name': '小汽车', 'stock': 3, 'price': 66666},
                {'id': 2, 'name': '小飞机', 'stock': 5, 'price': 55555},
                {'id': 3, 'name': '小火车', 'stock': 78, 'price': 88888},
                {'id': 4, 'name': '小游轮', 'stock': 976, 'price': 77777},
                {'id': 5, 'name': '小潜艇', 'stock': 786, 'price': 33333},
                {'id': 6, 'name': '小导弹', 'stock': 56, 'price': 22222},
                {'id': 7, 'name': '小趴菜', 'stock': 36, 'price': 999999},
            ],
            check_group: [],
            checkAll: false,
        },
        methods: {
            sumPrice() {
                // 计算总价格  根据 check_group 内的数据
                // check_group 循环取出价格和数量
                var total = 0;
                for (item of this.check_group) {
                    total += item.stock * item.price
                }
                return total
            },
            selectALL() {
                // 全选中,js中意思是  check_group 满值
                if (this.checkAll) {
                    this.check_group = this.good_list

                } else {
                    this.check_group = []
                }
            },
            selectOne() {
                // 判断 check_group 的长度是否等于 good_list 的长度
                if (this.check_group.length === this.good_list.length) {
                    this.checkAll = true
                } else {
                    this.checkAll = false
                }
            },
        }
    })
</script>
  • 带数量加减
</body>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            good_list: [
                {'id': 1, 'name': '小汽车', 'stock': 3, 'price': 66666},
                {'id': 2, 'name': '小飞机', 'stock': 5, 'price': 55555},
                {'id': 3, 'name': '小火车', 'stock': 78, 'price': 88888},
                {'id': 4, 'name': '小游轮', 'stock': 976, 'price': 77777},
                {'id': 5, 'name': '小潜艇', 'stock': 786, 'price': 33333},
                {'id': 6, 'name': '小导弹', 'stock': 56, 'price': 22222},
                {'id': 7, 'name': '小趴菜', 'stock': 36, 'price': 999999},
            ],
            check_group: [],
            checkAll: false,
        },
        methods: {
            sumPrice() {
                // 计算总价格  根据 check_group 内的数据
                // check_group 循环取出价格和数量
                var total = 0;
                for (item of this.check_group) {
                    total += item.stock * item.price
                }
                return total
            },
            selectALL() {
                // 全选中,js中意思是  check_group 满值
                if (this.checkAll) {
                    this.check_group = this.good_list

                } else {
                    this.check_group = []
                }
            },
            selectOne() {
                // 判断 check_group 的长度是否等于 good_list 的长度
                if (this.check_group.length === this.good_list.length) {
                    this.checkAll = true
                } else {
                    this.checkAll = false
                }
            },
            controlNum(good){
                if (good.stock>1){
                    good.stock--;
                }else{
                    alert("不能小于一件")
                }
            },
        }
    })
</script>

【补充】前后端交互的三种方式

  • 前后端要打通----》从前端发送ajax---》核心:使用js发送http请求,接收返回
    • 使用原生 JavaScript 发送 Ajax 请求
      • 这是一种传统的方式,通过使用 JavaScript 的 XMLHttpRequest 对象来发送和接收数据。
      • 开发者需要手动处理请求和响应的各个阶段,包括请求参数的拼装、请求头的设置、监听响应事件等。
      • 尽管这种方法具有灵活性,但是编写和维护复杂度较高,需要考虑不同浏览器的兼容性问题。
    • 使用 jQuery 的 Ajax 方法
      • jQuery 提供了方便的 $.ajax() 方法,封装了原生的 XMLHttpRequest 对象,简化了开发者的操作流程。
      • 它支持跨浏览器兼容性,并提供了丰富的功能选项,如设置请求类型、请求头、处理错误等。
      • 然而,由于现代前端框架(如 Vue.js)一般不推荐使用 jQuery,因此在与这些框架结合使用时可能不太适合。
    • 使用第三方库(如 Axios 或 Fetch)
      • 第三方库如 Axios 和 Fetch 提供更简洁、易用且功能强大的方式来发送 Ajax 请求。
      • 它们以 Promise 或 async/await 为基础,使得异步请求代码更加清晰和易于维护。
      • Axios 是一个流行的第三方库,广泛应用于前端项目中。
      • 同时,原生的 Fetch API 也是一种现代的标准方式,但需要注意兼容性问题
    • fetch: 原生js发送ajax请求,有的浏览器也不兼容

【1】使用jQuery的Ajax

  • 后端
# flask框架构建后端入口
from flask import Flask, jsonify

app = Flask(__name__)


@app.route('/')
def index():
    res = jsonify({"username": 'dream', "age": 20})
    # 前后端分离后,一定会出跨域---》后面要解决的重点
    # 在响应头中加入:Access-Control-Allow-Origin ,就就可以解决跨域
    res.headers = {'Access-Control-Allow-Origin': '*'}

    return res


if __name__ == '__main__':
    app.run()
  • 前端
<body>
<div id="app">

    <button @click="load">点我加载数据</button>
    <br>
    姓名::>>{{username}}
    <br>
    年龄::>>{{age}}
</div>
</body>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            username: "",
            age: "",
        },
        methods: {
            load() {
                // (1)后端交互方式一 : jQuery的Ajax
                // 请求发送成功,后端执行了,但是被浏览器拦截了,因为有跨域问题
                // 当前地址,如果向非浏览器地址栏中得地址发送请求,就会出现跨域
                var _this = this
                $.ajax({
                    url: 'http://127.0.0.1:5000',
                    type: 'get',
                    success: function (data) {
                        data = JSON.parse(data)
                        _this.username = data.username
                        _this.age = data.age
                    }
                })
            },
        }
    })
</script>

【2】使用JS原生的fetch

<body>
<div id="app">

    <button @click="load">点我加载数据</button>
    <br>
    姓名::>>{{username}}
    <br>
    年龄::>>{{age}}
</div>
</body>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            username: "",
            age: "",
        },
        methods: {
            load() {
                // 2 使用js原生的fetch(目前也不用)
                // fetch('http://127.0.0.1:5000').then(function (response) {
                //     // console.log(response)
                //     return response.json();
                // }).then(function (res) {
                //     console.log(res);
                // });
                
                fetch('http://127.0.0.1:5000').then(res => res.json()).then(res => {
                    console.log(res)
                })
            }
        }
    })
</script>

【3】使用axios

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <!-- Vue 的 JS 文件 -->
    <script src="vue.min.js"></script>

    <!--  CDN 链接 引入方法  -->
    <!--  jQuery 文件  -->
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.0/jquery.min.js">//jQuery</script>
    <!--  Bootstrap 的 CSS 样式文件  -->
    <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css">
    <!--  Bootstrap 的 JS 文件 (动画效果需要jQuery)  -->
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js">// bootstrap </script>
    <!--  Vue 文件  -->
    <!--    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.7.9/vue.min.js"></script>-->
    <!--  axios 文件  -->
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.6/axios.min.js"></script>

    <!--  以下为 css样式书写区  -->
    <style>


    </style>

</head>
<body>
<div id="app">

    <button @click="load">点我加载数据</button>
    <br>
    姓名::>>{{username}}
    <br>
    年龄::>>{{age}}
</div>
</body>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            username: "",
            age: "",
        },
        methods: {
            load() {
                // 使用axios(以后用这个)
                var _this = this
                axios.get('http://127.0.0.1:5000').then(function (res) {
                    console.log(res.data)
                    _this.username = res.data.username
                    _this.age = res.data.age
                })
            }
        }
    })
</script>
</html>

【补充】箭头函数

  • 函数写法变简单
  • 箭头函数没有自己的this,在箭头函数中使用this,就是它上一层的

【1】简解

  • 箭头函数是ES6中的语法特性,它提供了一种更简洁的函数定义方式。
  • 相比传统函数,箭头函数具有以下特点:
    • 简化的语法:
      • 箭头函数的语法非常简洁,可以帮助我们更快速地编写函数。
    • 没有自己的this:
      • 箭头函数没有自己的this绑定,它的this指向的是它被定义时所处的词法环境中的this值。
      • 这就意味着在箭头函数中使用this,实际上是使用了上一层作用域中的this。
// 传统函数
function multiply(a, b) {
  return a * b;
}

// 箭头函数
const multiply = (a, b) => a * b;

// 传统函数
function printName(name) {
  console.log(`My name is ${name}`);
}

// 箭头函数
const printName = (name) => {
  console.log(`My nam
  • 我们可以看到箭头函数的语法更加简洁
    • 去掉了function关键字和花括号
    • 并且还可以省略return关键字(如果只有一个表达式的话)。
  • 同时,在箭头函数中,在使用this时,它会继承外部作用域的this值,而不是创建自己的this。
  • 需要注意的是,由于箭头函数没有自己的this,因此它也不能被用作构造函数,并且不能使用call、apply和bind方法来改变this的指向。
  • 另外,在箭头函数中也无法使用arguments对象,但可以使用 ...rest 参数来替代。

【2】演示

  • 无参数,无返回值
var f = function () {
    console.log('我是匿名函数')
}
var f = () => {
    console.log('我是匿名函数')
}
f()
  • 有一个参数,没有返回值 ,可以省略括号
var f = function (name) {
    console.log('我是匿名函数', name)
}
var f = name => {
    console.log('我是匿名函数', name)
}
f('dream')
  • 多个参数,不能省略括号
var f = (name, age) => {
    console.log('我是匿名函数', name, age)
}
f('dream', 19)
  • 多个参数,不能省略括号,一个返回值
var f = (name, age) => {
    return name + 'nb'
}

// 简写成  省了return和大括号
var f = (name, age) => name + 'nb'
var res=f('dream', 19)
console.log(res)
  • 一个参数,一个返回值
var f = name => name + 'nb'
var res = f('dream')
console.log(res)

【补充】JS中的for循环操作

//补充: js循环
var arr = [33, 2, 3, 4, 6, 7, 4]
// 1 基础for循环
// for (var i = 0; i < arr.length; i++) {
//     console.log(arr[i])
// }
// 2 in的循环(不怎么用),循环出索引
// for (i in arr) {
//     // console.log(i)
//     console.log(arr[i])
// }

//3 of 循环  es6的语法  循环出value值
// for (i of arr) {
//     console.log(i)
// }


// 4 数组的循环
// arr.forEach(function (value, index) {
//     console.log(index, '--', value)
// })

// 5 jq的循环
// $.each(arr, function (index, value) {
//     console.log(index, '--', value)
// })

【补充】数组的过滤

  • 数组.filter(匿名函数,接收一个参数,函数必须返回 true/false )
    • 返回 true 则表示该数据保留
var arr = ['a', 'at', 'atom', 'attoo', 'be', 'beyond', 'cs', 'csrf']
    // 数组.filer(匿名函数,接受一个参数,函数必须返回true或false,如果返回true,表示这个值保留)
    var new_arr = arr.filter(function (item) {
        console.log(item)
        if (item.length > 3) {
            return true
        } else {
            return false
        }

    })
    console.log(new_arr)
  • 判断一个字符串是否在另一个字符串中
var s='is'
var s1 = 'lqz is handsome'
var res=s1.indexOf(s)   // s的索引位置,如果大于等于0,说明s在s1中
console.log(res)
  • 过滤出数组中有at的字符串
var arr = ['a', 'at', 'atom', 'attoo', 'be', 'beyond', 'cs', 'csrf']
    var search = 'at'
    var new_arr = arr.filter(function (item) {

        if (item.indexOf(search) >= 0) {
            return true
        } else {
            return false
        }

    })
    console.log(new_arr)

【补充】vm对象简解

<body>
<div id="app">
    <!--插值语法-->
    <h1>{{name}}</h1>
    <br>
    <h2> 方法中的 this 对象 </h2>
    <button @click="handleClick1">点我</button>
</div>
</body>

<script>
    <!--  将创建的Vue对象封装到 vm 变量里面。控制台全局可以通过 vm.name 取值  -->
    // 写在 data 或 methods 中的属性或方法,可以从 vm 中直接 通过 vm.属性取值
    // methods的函数中,如果想使用data或methods中的属性,直接this.名字  就可以了
    var vm = new Vue({
        el: "#app",
        data: {
            name: "dream",
        },
        methods: {
            handleClick1() {
                console.log(this) // this 就是当前的 实例的 vm 对象
                // xr {_uid: 0, _isVue: true, __v_skip: true, _scope: t, $options: {…}, …}
            }
        },
    })
</script>
  • vm是一个Vue实例对象的变量名。

    • Vue实例对象是Vue.js框架中最核心的概念之一,它扮演着连接数据和视图的桥梁作用。

    • 数据绑定:

      • 通过将vm对象传递给模板语法,可以实现数据的动态渲染。
      • 例如,在模板中使用{{name}}的插值语法,name会被vm对象中的data属性中的name所替换,从而实现了name数据的动态展示。
    • 方法调用:

      • vm对象的methods属性中定义的方法,可以通过模板中的事件绑定(如@click="handleClick1")来进行调用。
      • 在这个例子中,当点击按钮时,会触发handleClick1方法,输出this对象。
      • 在方法中,this指向当前的Vue实例对象vm,通过this可以访问到vm实例中的属性和方法。
  • 总结起来,vm对象是Vue实例对象的引用,通过这个对象可以访问和操作Vue实例的数据和方法。

    • 它的作用是管理数据和行为,实现数据的双向绑定,以及处理用户交互和响应。
    • 在模板中可以通过vm对象来访问数据,并触发相应的方法来实现业务逻辑的处理。

【补充】es6的简写推导

// es6的简写形式
var a = {"name": "dream", "age": 19}
var b = {name: "dream", age: 19} // 一次简写
var name = "dream"
var age = 19
var f = function (){}
var d = {"name": name, "age": age,"f":function () {}} // 二次简写
var e = {name, age,f} // 三次简写 ---> {"name": name, "age": age,f:function () {}}