【无标题】Vue语法

本文深入探讨Vue.js的高级特性,包括事件操作(事件绑定、事件对象、带参数事件、事件修饰符)和数据双向绑定(MVVM、表单处理、自定义框架)。详细讲解了事件修饰符如.stop、.prevent等的用法,并通过实例演示了如何处理事件冒泡和阻止默认行为。此外,还介绍了表单的v-model指令用于数据双向绑定,并讨论了数据变化监听的底层实现——数据劫持。最后,简述了自定义Vue框架的基本步骤。
摘要由CSDN通过智能技术生成

Vue语法进阶

课程大纲

1、事件操作

2、表单处理

3、MVVM数据双向绑定(面试)

4、自定义框架

1、事件操作

事件event对象是脚本开发中一个非常重要的对象,Vue中对事件和事件对象进行了良好的支持

(1) 事件绑定

通过v-on:事件名称绑定事件操作,语法上可以优化为@事件名称完成事件的绑定操作!

(2) 事件对象

事件操作函数不带参数的时候,事件处理函数的第一个形式参数,默认就是事件对象!这里也不需要添加兼容性写法

const vm = new Vue({
    ...
    methods: {
        handlerMsg(e) {
            // e = e || window.event
            // 直接使用e 事件对象
        }
    }
})

(3) 带参数的事件对象

事件操作函数如果附带参数的情况下,Vue提供了显式的事件对象:$event,用于事件函数传参

<div>
    <input type="text" @keyup="handleDelEvnet($event, 10)" />
</div>
...
<script>
	const vm = new Vue({
        ...
        methods: {
            handleDelEvnet(e, index) {
                // 处理事件对象e 和参数数据index
            }
        }
    })
</script>

(4) 事件修饰符

事件操作过程中,会包含很多事件的附加操作,如阻止默认行为、阻止事件冒泡、事件一次性触发等等,Vue中提供了对应的事件修饰符,可以在事件绑定时直接完成关联

  • .stop:阻止事件冒泡
  • .prevent:阻止默认行为
  • .capture:捕获触发
  • .once:一次性触发
  • .self:独立触发
  • .passive:滚动行为

思考;原生JS中和事件相关的一些兼容性问题,整理出来!

(6) 案例操作

和事件相关的案例代码:demo02事件操作.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #app{height:2000px;}
        .outer{width: 500px; background:orange;padding: 10px;}
        .inner{width: 300px; background: red; padding: 10px;}
    </style>
</head>
<body>
    <div id="app">
        <!-- 1、事件绑定,通过v-on指令进行操作 -->
        <div>
            <button @click="handleEvent">1、事件绑定</button>
        </div>
        <!-- 2、事件对象,获取鼠标位置-->
        <div>
            <button @click="handleEvent2">2、直接操作事件对象</button>
        </div>
        <!-- 3、事件对象,传递参数数据-->
        <div>
            <h5>3、带参数的情况下传递事件对象</h5>
            <input type="text" @keyup="handleDelEvent($event, 10)">
        </div>
        <!-- 4、事件触发修饰符 -->
        <div>
            <div class="outer" @click="handleOuter">
                <div class="inner" @click="handleInner">
                    <button @click.stop="handleTarget">点击按钮,阻止冒泡: .stop</button>
                </div>
            </div>
        </div>
        <div>
            <a href="https://www.baidu.com" @click.prevent="handleMsg">百度一下,阻止默认行为: .prevent</a>
        </div>
        <div>
            <button id="btn" @click.once="handlerOnce">点击我试试,一次性事件: .once</button>
        </div>
        <div>
            <div class="outer" @click.capture="handleOuter">
                <div class="inner" @click.capture="handleInner">
                    <button @click="handleTarget">点击按钮,捕获触发->冒泡触发: .capture</button>
                </div>
            </div>
        </div>
        <div>
            <div class="outer" @click="handleOuter">
                <div class="inner" @click.self="handleInner">
                    <button @click="handleTarget">点击按钮,事件独立触发: .self</button>
                </div>
            </div>
        </div>
        <div>
            <div class="outer" @click="handleOuter">
                <div class="inner" @click="handleInner">
                    <a href="https://www.baidu.com" @click.prevent.stop="handleMsg">百度一下 如何阻止冒泡的同时阻止默认行为?</a>
                </div>
            </div>
        </div>
    </div>
    <button id="btn">点击我试试,一次性事件</button>
    
    <script src="./vue.js"></script>
    <script>
        // let btn = document.querySelector("#btn")
        btn.onclick = function() {
            alert("考试结算")
            btn.onclick = null;
        }
        
        const vm = new Vue({
            el: "#app",
            methods: {
                handleEvent() {
                    alert("事件被触发了.")
                },
                handleEvent2(e) {
                    console.log("事件对象", e)
                    console.log(e.clientX, e.clientY, "浏览器窗口")
                    console.log(e.pageX, e.pageY, "网页文档")
                    console.log(e.screenX, e.screenY, "屏幕窗口")
                },
                handleDelEvent(e, index) {
                    console.log("要删除的数据索引:" + index)
                    console.log("要删除的数据值:" + e.target.value)
                },

                handleTarget() {
                    console.log("按钮被点击了")
                },
                handleInner() {
                    console.log("inner div 被点击了")
                },
                handleOuter() {
                    console.log("outer div 被点击了")
                },

                handleMsg() {
                    console.log("该功能正在升级中...")
                },
                handlerOnce() {
                    console.log("用户点击了按钮")
                }
            }
        })
    </script>
</body>
</html>

2、表单操作

网页中有一个非常重要的组件:表单,完成了用户对数据的输入!

Vue中提供了一个非常重要的指令:v-model,用于自动接受用户输入的数据!

代码操作:demo02表单操作.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="app">
        <form action="">
            <div>
                <label for="username">账号</label>
                <input type="text" v-model="formData.username">
                <span>{{ formData.username }}</span>
            </div>
            <div>
                <label for="password">密码</label>
                <input type="password" v-model="formData.password">
                <span>{{ formData.password }}</span>
            </div>
            <div>
                <label for="age">年龄</label>
                <input type="text" v-model="formData.age">
                <span>{{ formData.age }}</span>
            </div>
            <div>
                <label for="gender">性别</label>
                <input type="radio" name="gender" value="男" v-model="formData.gender">男
                <input type="radio" name="gender" value="女" v-model="formData.gender">女
                <span>{{ formData.gender }}</span>
            </div>
            <div>
                <label for="fav">爱好</label>
                <input type="checkbox" name="fav" value="篮球" v-model="formData.fav">篮球
                <input type="checkbox" name="fav" value="旅游" v-model="formData.fav">旅游
                <input type="checkbox" name="fav" value="电影" v-model="formData.fav">电影
                <input type="checkbox" name="fav" value="阅读" v-model="formData.fav">阅读
                <input type="checkbox" name="fav" value="游戏" v-model="formData.fav">游戏
                <span>{{formData.fav}}</span>
            </div>
            <div>
                <label for="address">地址</label>
                <select v-model="formData.address">
                    <option value="郑州">郑州</option>
                    <option value="广州">广州</option>
                    <option value="兰州">兰州</option>
                    <option value="苏州">苏州</option>
                    <option value="杭州">杭州</option>
                    <option value="柳州">柳州</option>
                </select>
                <span>{{formData.address}}</span>
            </div>
            <div>
                <label for="introduction">简介</label>
                <textarea cols="30" rows="3" v-model="formData.introduction"></textarea>
                <span>{{formData.introduction}}</span>
            </div>
            <div>
                <input type="submit" value="提交" @click.prevent="submit">
            </div>
        </form>
    </div>
    
    <script src="./vue.js"></script>
    <script>
        const vm = new Vue({
            el: "#app",
            data: {
                formData: {
                    username: '',
                    password: '',
                    age: '',
                    gender: '',
                    fav: [],
                    address: '',
                    introduction: ''
                }
            },
            methods: {
                submit() {
                    console.log("用户准备提交表单,验证数据,发送ajax请求")
                    console.log(this.formData)
                    // $.ajax({
                    //     url: "http://localhost:3000/api/login",
                    //     type: "post",
                    //     data: this.formData,
                    //     success: res => {
                    //         if(res.code === 200) {

                    //         }
                    //     }
                    // })
                }
            }
        })
    </script>
</body>
</html>

3、数据双向绑定

(1) 什么是数据双向绑定

所谓数据双向绑定,是出现在前端应用中的一个专业术语,描述了数据在界面和数据处理部分之间的关联关系,数据在视图界面和脚本数据处理部分实现了双向关联,所以称这样的操作模式为数据双向绑定,简称MVVM

代码操作:

<body>
    <div id="app">
        <input type="text" v-model="name">
        <p>用户输入的数据:{{name}}</p>
    </div>
    
    <script src="./vue.js"></script>
    <script>
        const vm = new Vue({
            el: "#app",
            data: {
                name: "DAMU"
            }
        })
    </script>
</body>

备注:表单的操作,也可以添加表单修饰符、按键修饰符

表单修饰符:

  • v-model.trim:剔除输入数据两侧的空格
  • v-model.number:将数据转换成数值,如果转换不成功就什么都不做
  • v-model.lazy:延迟数据同步,失去焦点的时候再完成同步

按键修饰符:

  • @click.enter:按下回车键
  • @click.esc:按下esc
  • ...

(2) 数据双向绑定的问题

编写一个添加用户名称的案例,核心操作通过事件函数向数组中添加数据并完成页面上的数据渲染

① 正确的添加和渲染

this.names.push(this.name)	// 添加数据【成功】,渲染数据【成功】

② 出现问题的添加

this.names[this.names.length] = this.name    // 添加数据【成功】,渲染数据【失败】

总结:渲染失败的问题

Vue中存在一种机制,可以监听变量中的数据是否发生变化,一旦数据发生变化就需要通知页面进行更新;假设这样的机制监听了数组的push函数,所以push()数据时添加和渲染都没有问题;但是没有监听通过下标进行添加数据的操作,所以下标增加数据成功但是无法在页面上完成渲染!

浏览器控制台打开vm实例,查看names属性时,发现原型对象上挂载了数组的部分函数(接收vue实例进行管理和监听的,当数组中的数据经过这些函数完成数据更新,会自动完成数据渲染);这部分函数以外的其他操作方式可能会改变数组数据但是不会引起页面重新渲染!

思考:这样的监听方式(如何监听变量数据的变化),底层是如何实现的?

补充:如果一定要通过索引的方式完成数据的添加Vue2.x版本中,提供了一个系统函数$set()可以完成数据的添加和渲染

// 3、使用框架内建函数完成
// this/vm.$set(数组, 索引, 数据)
this.$set(this.names, this.names.length, this.name)

(3) 底层实现原理

Vue中底层对变量进行了 数据劫持(变量的一种声明方式),就可以监控变量中数据的变化,也是Vue中数据双向绑定的底层实现原理,如图所示:

代码操作:数据劫持完成变量声明

<body>
    <div id="app">

    </div>
    <script>
        // 1、声明一个可以被监听的变量
        /***************************************************/
        let myNameTemp = "DAMU" // 存储数据的初始值
        // 数据劫持定义:在window对象上声明变量myName
        Object.defineProperty(window, "myName", {
            get() {
                console.log("get函数被调用了")
                return myNameTemp
            },
            set(val) {
                console.log("set函数被调用了")
                myNameTemp = val
                // 2、数据双向绑定中,数据的自动渲染(发布订阅--通知机制)
                render()
            }
        })
        /***************************************************/

        function render() {
            app.innerText = myName
        }
        render()
    </script>
</body>

小总结:

关于数据劫持的代码,不需要熟悉!

  • 需要掌握:数据双向绑定底层实现原理,就是数据劫持
  • 数据劫持:是一种变量的声明方式,用来声明可以被监听的变量
  • 数据劫持通过Object.defineProperty()系统函数实现

4、 自定义Vue框架

① 文件结构初始化

项目中创建myvue.js

/**
 * 自定义vue框架
 *  V1.0
 */

项目中创建demo06自定义vue.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="app">
        
    </div>
    
    <script src="./myvue.js"></script>
    <script>

    </script>
</body>
</html>

② 页面开发

编辑demo06自定义vue.html,添加Vue实例的创建、变量数据的声明、函数的声明

<body>
    <div id="app">
        <p>{{ name }}</p>
        <p>{{age}}</p>
        <p>{{introduction()}}</p>
    </div>
    
    <script src="./myvue.js"></script>
    <script>
        const vm = new Vue({
            el: "#app",
            data: {
                name: "大牧",
                age: 18
            },
            methods: {
                introduction() {
                    console.log(`姓名:${this.name};年龄:${this.age}`)
                }
            }
        })
    </script>
</body>

③ 基础类型声明

编辑myvue.js,添加Vue类型声明

/**
 * 自定义vue框架
 *  V1.0
 */
class Vue {

    constructor(props) {
        console.log(props)
    }

}

④ 接受并处理数据

编辑myvue.js,完成el、data、methods数据的接受

constructor(props) {
    // 接受el标签
    this.$el = document.querySelector(props.el)
    this._html = this.$el.innerHTML

    // 接受data数据
    this._data = {...props.data}
    for(let key in this._data) {
        Object.defineProperty(this, key, {
            get() {
                return props.data[key]
            },
            set(val) {
                this._data[key] = val
            }
        })
    }

    // 接受methods函数数据
    for(let key in props.methods) {
        this[key] = props.methods[key]
    }
}

⑤ 渲染页面

编辑myvue.js,通过字符串操作完成页面数据的替换

// 渲染页面数据的函数
render() {
    let reg = /\{\{\s*(\w*\(?\)?)\s*\}\}/g;
    let newHtml = this._html.replace(reg, (a, b) => {
        console.log(a, b, "正则替换")
        if(b.endsWith("()")) {
            // 这是一个函数,需要调用执行
            return this[b.substring(0, b.length-2)]()   // this['introduction()']()
        } else {
            // 这是一个变量,直接获取
            return this[b] // this['name']
        }
    })

    // console.log(newHtml, "newHtml")
    this.$el.innerHTML = newHtml
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值