vue2面试题11|[2024-11-25]

1.vue源码-模版解析

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>

<div id='app'>
    <h1> {{ str }} </h1>
    {{ str }}
</div>

</body>

<script type="text/javascript" src='vue.js'></script>
<script type="text/javascript">

new Vue({
    el:'#app',
    data: {
        str:'您好'
    }
})

</script>

</html>
class Vue{

        constructor(options){
            this.$el = document.querySelector(options.el)
            this.$data = options.data

            this.compile(this.$el)
        }

        compile(node){
            node.childNodes.forEach((item.index) => {
                // 元素节点
                if(item.nodeType == 1){
                    this.compile(item)
                }
                // 这里是文本节点,如果有{{}}就替换成数据
                if(item.nodeType == 3){
                    // 正则匹配
                    let reg = /\{\{(.*?)\}\}/g
                    let text = item.textContent
                    // 给节点赋值
                    item.textContent = text.replacce(reg,(match,vmKey) => {
                        vmKey = vmKey.trim()
                        return this.$data[vmKey]
                    })
                }
            })
        }

}

 2.vue源码-生命周期

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>

<div id='app'>
    <h1> {{ str }} </h1>
    {{ str }}
</div>

</body>

<script type="text/javascript" src='vue.js'></script>
<script type="text/javascript">

new Vue({
    el:'#app',
    data: {
        str:'您好'
    },
    created(){
        console.log('created',this.$el, this.$data)
    }
    beforeCreate(){
        console.log('beforeCreate',this.$el, this.$data)
    }
    mounted(){
        console.log('mounted',this.$el, this.$data)
    }
    beforeMount(){
        console.log('beforeMount',this.$el, this.$data)
    }
})

</script>

</html>

得到的结果应该是:

beforeCreate undefined undefined

created undefined data

beforeMount undefined data

mounted  el data

class Vue{

        constructor(options){
            if(typeof options.beforeCreate == 'function'){
                options.beforeCreate.bind(this)()
            }
            // 这是data
            this.$data = options.data

            if(typeof options.created == 'function'){
                options.beforeCreate.bind(this)()
            }
            if(typeof options.beforeMount == 'function'){
                options.beforeCreate.bind(this)()
            }
            // 这是节点
            this.$el = document.querySelector(options.el)
            // 模板渲染
            this.compile(this.$el)
            if(typeof options.mounted == 'function'){
                options.beforeCreate.bind(this)()
            }
            
        }

        compile(node){
            node.childNodes.forEach((item.index) => {
                // 元素节点
                if(item.nodeType == 1){
                    this.compile(item)
                }
                // 这里是文本节点,如果有{{}}就替换成数据
                if(item.nodeType == 3){
                    // 正则匹配
                    let reg = /\{\{(.*?)\}\}/g
                    let text = item.textContent
                    // 给节点赋值
                    item.textContent = text.replacce(reg,(match,vmKey) => {
                        vmKey = vmKey.trim()
                        return this.$data[vmKey]
                    })
                }
            })
        }

}

 3.vue源码-添加事件

<body>

    <h1>{{str}}</h1>
    <p>{{str}}</p>
    <button @click='btn'>按钮</button>
</body>

<script type="text/javascript">
new Vue({
    el: '#app',
    data:{
        str:'您好'
    },
    methods:{
        btn(){
            console.log(this.str)   // undefined
        }
    }
})
</script>

注意这里点击按钮,并不能得到str的数据,还是undefined,因为如下图,其中并没有str,要得到str的数据,应该执行this.$data.str,但是对于实际应用中,执行的是this.str,所以还需要改变。

this.$options = options

compile(node){
   node.childNodes.forEach((item.index) => {
       // 元素节点
       if(item.nodeType == 1){
            // 判断元素节点是否绑定了@click
            if(item.hasAttribute('@click')){
                // @click后绑定的属性值
                let vmKey = item.getAttribute('@click').trim()
                item.addEventListener('click',(event) => {
                    this.eventFn = this.$options.methods[vmKey].bind(this)
                    this.eventFn(event)
                })
            }
            if(item.childNodes.length>0){
                this.compile(item)
            }
          
       }
       // 这里是文本节点,如果有{{}}就替换成数据
       if(item.nodeType == 3){
          // 正则匹配
          let reg = /\{\{(.*?)\}\}/g
          let text = item.textContent
          // 给节点赋值
          item.textContent = text.replacce(reg,(match,vmKey) => {
               vmKey = vmKey.trim()
               return this.$data[vmKey]
          })
         }
    })
}

 4.vue源码-data劫持

<body>

    <h1>{{str}}</h1>
    <p>{{str}}</p>
    <button @click='btn'>按钮</button>
</body>

<script type="text/javascript">
new Vue({
    el: '#app',
    data:{
        str:'您好'
    },
    methods:{
        btn(){
            console.log(this.str)   // 123
            this.str = 456
            console.log(this.str)   // 456,但是视图并不会改变
        }
    }
})
</script>

想要直接通过this.str获得数据,就要在vue外部添加数据

vue{

        $data:{str:123,b:'456'}

        $el

        options

        eventFn

        str:123

        b:'456'

}

注意:其中存在一个问题,就是修改其中的数据,视图并没有改变,若想视图发生改变,就需要使用innerHTML、innerText、textContent

class Vue{
        constructor(options){
            this.$options = options
            this.proxyData()
            if(typeof options.beforeCreate == 'function'){
                options.beforeCreate.bind(this)()
            }
            // 这是data
            this.$data = options.data

            if(typeof options.created == 'function'){
                options.beforeCreate.bind(this)()
            }
            if(typeof options.beforeMount == 'function'){
                options.beforeCreate.bind(this)()
            }
            // 这是节点
            this.$el = document.querySelector(options.el)
            // 模板渲染
            this.compile(this.$el)
            if(typeof options.mounted == 'function'){
                options.beforeCreate.bind(this)()
            }
            
        }
        
    // 1.给vue大对象赋属性,来自于data中
    // 2.data中的属性值和vue大对象的属性双向(劫持)
    proxyData(){
        for(let key in this.$data){
            Object.defineProperty(this,key,{
                get(){
                    return this.$data[key]
                },
                set(val){
                    this.$data[key] = val
                }
            })
        }
    }
}

5.vue源码-更新视图

经过劫持data,发现修改数据之后,会发生数据改变了,但是视图并没有改变

class Vue{
        constructor(options){
            this.$options = options
            this.$watchEvent = {}
            
            if(typeof options.beforeCreate == 'function'){
                options.beforeCreate.bind(this)()
            }
            // 这是data
            this.$data = options.data
            this.proxyData()
            this.observe()
            if(typeof options.created == 'function'){
                options.beforeCreate.bind(this)()
            }
            if(typeof options.beforeMount == 'function'){
                options.beforeCreate.bind(this)()
            }
            // 这是节点
            this.$el = document.querySelector(options.el)
            // 模板渲染
            this.compile(this.$el)
            if(typeof options.mounted == 'function'){
                options.beforeCreate.bind(this)()
            }
            
        }
        
    // 1.给vue大对象赋属性,来自于data中
    // 2.data中的属性值和vue大对象的属性双向(劫持)
    proxyData(){
        for(let key in this.$data){
            Object.defineProperty(this,key,{
                get(){
                    return this.$data[key]
                },
                set(val){
                    this.$data[key] = val
                }
            })
        }
    }

    // 触发data中的数据发生变化来执行watch中的update
    observe(){
        for(let key in this.$data){
            let value = this.$data[key]
            let that = this
            Object.defineProperty(this.$data,key,{
                get(){
                    return value
                },
                set(val){
                    value = val
                    if(that.$watchEvent[key]){
                        that.$watchEvent[key].forEach((item,index) => {
                            item.update()
                        })
                    }
                }
            })
        }
    }
   compile(node){
       node.childNodes.forEach((item.index) => {
           // 元素节点
           if(item.nodeType == 1){
                // 判断元素节点是否绑定了@click
                if(item.hasAttribute('@click')){
                    // @click后绑定的属性值
                    let vmKey = item.getAttribute('@click').trim()
                    item.addEventListener('click',(event) => {
                        this.eventFn = this.$options.methods[vmKey].bind(this)
                        this.eventFn(event)
                    })
                }
                if(item.childNodes.length>0){
                    this.compile(item)
                }
          
           }
           // 这里是文本节点,如果有{{}}就替换成数据
           if(item.nodeType == 3){
              // 正则匹配
              let reg = /\{\{(.*?)\}\}/g
              let text = item.textContent
              // 给节点赋值
              item.textContent = text.replacce(reg,(match,vmKey) => {
                   vmKey = vmKey.trim()

                    if(this.hasOwnProperty(vmKey)){
                        let watch = new Watch(this,vmKey,item,'textContent')
                        if(this.$watchEvent[vmKey]){
                            this.$watchEvent[vmKey].push(watch)
                        }else{
                            this.$watchEvent[vmKey] = []
                            this.$watchEvent[vmKey].push(watch)
                        }
                    }
                   return this.$data[vmKey]
               })
             }
        })
    }
}

class Watch{
    constructor(vm,key,node,attr){
        // 对象
        this.vm = vm
        // 属性名称
        this.key = key
        // 节点
        this.node = node
        // 改变文本节点内容的字符串
        this.attr = attr
    }

    //执行改变(update)操作
    update(){
        this.node[this.attr] = this.vm[this.key]
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/924418.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

web博客系统的自动化测试

目录 前言测试用例编写自动化脚本测试准备博客登录页相关测试用例登陆成功登录失败 博客首页相关测试用例登陆成功登录失败 博客详情页相关测试用例登录成功登录失败 博客编辑页相关测试用例登陆成功登录失败 编写测试文档测试类型内容 前言 本次测试是运用个人写的一个博客系…

MATLAB矩阵元素的修改及删除

利用等号赋值来进行修改 A ( m , n ) c A(m,n)c A(m,n)c将将矩阵第 m m m行第 n n n列的元素改为 c c c&#xff0c;如果 m m m或 n n n超出原来的行或列&#xff0c;则会自动补充行或列&#xff0c;目标元素改为要求的&#xff0c;其余为 0 0 0 A ( m ) c A(m)c A(m)c将索引…

告别 Kafka,拥抱 Databend:构建高效低成本的用户行为分析体系

用户行为数据埋点指标是数据仓库中不可或缺的重要数据源之一&#xff0c;同时也是企业最宝贵的资产之一。通常情况下&#xff0c;用户行为数据分析包含两大数据源&#xff1a;用户行为分析日志和上游关系型数据库&#xff08;如 MySQL&#xff09;。基于这些数据&#xff0c;企…

WEB攻防-通用漏洞文件上传中间件解析漏洞编辑器安全

中间件文件解析-IIS&Apache&Nginx Web应用编辑器-Ueditor文件上传安全 实例CMS&平台-中间件解析&编辑器引用 Vulhub是一个基于docker和docker-compose的漏洞环境集合&#xff0c;进入对应目录并执行一条语句即可启动一个全新的漏洞环境&#xff0c;让漏洞复现…

【算法day1】数组:双指针算法

题目引用 这里以 1、LeetCode704.二分查找 2、LeetCode27.移除元素 3、LeetCode977.有序数组的平方 这三道题举例来说明数组中双指针的妙用。 1、二分查找 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜…

快速理解微服务中Sentinel怎么实现限流

Sentinel是通过动态管理限流规则&#xff0c;根据定义的规则对请求进行限流控制。 一.实现步骤 1.定义资源&#xff1a;在Sentinel中&#xff0c;资源可以是URL、方法等&#xff0c;用于标识需要进行限流的请求&#xff1b;(在Sentinel中&#xff0c;需要我们去告诉Sentinel哪些…

controller中的参数注解@Param @RequestParam和@RequestBody的不同

现在controller中有个方法&#xff1a;&#xff08;LoginUserRequest是一个用户类对象&#xff09; PostMapping("/test/phone")public Result validPhone(LoginUserRequest loginUserRequest) {return Result.success(loginUserRequest);}现在讨论Param("login…

OpenCV截取指定图片区域

import cv2 img cv2.imread(F:/2024/Python/demo1/test1/man.jpg) cv2.imshow(Image, img) # 显示图片 #cv2.waitKey(0) # 等待按键x, y, w, h 500, 100, 200, 200 # 示例坐标 roi img[y:yh, x:xw] # 截取指定区域 cv2.imshow(ROI, roi) cv2.waitKey(0) cv…

【经典】星空主题的注册界面HTML,CSS,JS

目录 界面展示 完整代码 说明&#xff1a; 这是一个简单的星空主题的注册界面&#xff0c;使用了 HTML 和 CSS 来实现一个背景为星空效果的注册页面。 界面展示 完整代码 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8&…

后端:事务

文章目录 1. 事务2. Spring 单独配置DataSource3. 利用JdbcTemplate操作数据库4. 利用JdbcTemplate查询数据5. Spring 声明式事务6. 事务的隔离级别6.1 脏读6.2 不可重复读6.3 幻读6.4 不可重复读和幻读的区别6.5 三种方案的比较 7. 事务的传播特性8. 设置事务 只读(readOnly)9…

vue element-ui的el-image 和 el-table冲突层级冲突问题问题preview-teleported

问题: 解决代码:preview-teleported <el-image style"width: 50px; height: 50px" :src"props.row.url" :zoom-rate"1.2" :max-scale"7":min-scale"0.2" :preview-src-list"[props.row.url]" :initial-index&…

vue3 开发利器——unplugin-auto-import

这玩意儿是干啥的&#xff1f; 还记得 Vue 3 的组合式 API 语法吗&#xff1f;如果有印象&#xff0c;那你肯定对以下代码有着刻入 DNA 般的熟悉&#xff1a; 刚开始写觉得没什么&#xff0c;但是后来渐渐发现&#xff0c;这玩意儿几乎每个页面都有啊&#xff01; 每次都要写…

FreeSWITCH 简单图形化界面34 - 网络环境安全的情况下,进行任意SIP注册

FreeSWITCH 简单图形化界面34 -网络环境安全的情况下&#xff0c;进行任意SIP注册 测试环境1、前言2、参数3、实践一下 测试环境 http://myfs.f3322.net:8020/ 用户名&#xff1a;admin&#xff0c;密码&#xff1a;admin FreeSWITCH界面安装参考&#xff1a;https://blog.cs…

基于Matlab深度学习的CT影像识别系统研究与实现

通过使用AlexNet、GoogLeNet和VGGNet等预训练模型&#xff0c;并结合迁移学习技术&#xff0c;对CT影像进行特征提取和分类。系统在公开数据集上进行了训练和测试&#xff0c;结果表明&#xff0c;该方法能够有效区分COVID-19和非COVID-19的CT影像&#xff0c;具有较高的准确率…

如何使用postman做接口测试?

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 常用的接口测试工具主要有以下几种&#xff1a; Postman: 简单方便的接口调试工具&#xff0c;便于分享和协作。具有接口调试&#xff0c;接口集管理&#…

数据分析的尽头是web APP?

数据分析的尽头是web APP&#xff1f; 在做了一些数据分析的项目&#xff0c;也制作了一些数据分析相关的web APP之后&#xff0c;总结自己的一些想法和大家分享。 1.web APP是呈现数据分析结果的另外一种形式。 数据分析常见的结果是数据分析报告&#xff0c;可以是PPT或者…

学习笔记037——Java中【Synchronized锁】

文章目录 1、修饰方法1.1、静态方法&#xff0c;锁定的是类1.2、非静态方法&#xff0c;锁定的是方法的调用者&#xff08;对象&#xff09; 2、修饰代码块&#xff0c;锁定的是传入的对象2.1、没有锁之前&#xff1a;2.2、有锁后&#xff1a; 实现线程同步&#xff0c;让多个线…

开源加密库mbedtls及其Windows编译库

目录 1 项目简介 2 功能特性 3 性能优势 4 平台兼容性 5 应用场景 6 特点 7 Windows编译 8 编译静态库及其测试示例下载 1 项目简介 Mbed TLS是一个由ARM Maintained的开源项目&#xff0c;它提供了一个轻量级的加密库&#xff0c;适用于嵌入式系统和物联网设备。这个项…

QTableWidget使用代理绘制分行显示

在这里插入代码片# 创建主窗口类&#xff1a; 使用 QTableWidget 作为核心控件。 设置表头及行列信息。 自定义代理&#xff1a; 继承 QStyledItemDelegate&#xff0c;实现代理模式。 重写 paint 和 sizeHint 方法&#xff0c;支持多行文本绘制。 设置行高以适应多行显示。 …

Python学习35天

# 定义父类 class Computer: CPUNone MemoryNone diskNone def __init__(self,CPU,Memory,disk): self.disk disk self.Memory Memory self.CPU CPU def get_details(self): return f"CPU:{self.CPU}\tdisk:{self.disk}\t…