当前位置: 首页 > Web前端 > vue.js

[fed-task-03-01]手写VueRouter,手写响应式,虚拟DOM和Diff算法

时间:2023-04-01 00:08:40 vue.js

文章内容输出来源:拉勾教育大前端高薪训练营文章内容包括:模块作业,学习笔记简答问题1,当我们点击按钮的时候,动态添加到数据中的成员是否是响应式数据,如果不是,如果新增成员设置为响应式数据,其内部原理是什么。letvm=newVue({el:'#el'data:{o:'object',dog:{}},method:{clickHandler(){//name属性是否响应式this.dog.name='Trump'}}})答:标题中this.dog.name='Trump'添加到dog的成员不是响应式数据。在Vue中,可以通过Vue.set(target,propertyName/index,value)或者this.$set(target,propertyName/index,value)向目标对象动态添加响应式数据。Vue2.x中的原理是:类似于调用defineReactive(obj,key,val)方法,使用Object.defineProperty的getter和setter实现响应式数据。2、请简述Diff算法的执行过程。答:DOM操作非常消耗性能,所以有必要尽量减少DOM操作。在DOM中找出本次必须更新的节点并更新,其他的不更新。这个“找出”过程需要一个差异算法。diff算法的主要执行过程:patch(container,vnode),第一次渲染,将container转化为vnode,比较新旧VNode是否是同一个节点,然后更新DOMpatch(vnode,newVnode),第二次渲染更改数据,比较新旧VNode是否为同一个节点然后更新DOMcreateElm(vnode,insertedVnodeQueue),先执行用户的inithook函数,然后将vnode转成真正的DOM(不渲染到页面中)这次),最后返回新创建的DOMupdateChildren(elm,oldCh,ch,insertedVnodeQueue),如果VNode有子节点,如果与旧VNode的子节点不同,则执行updateChildren(),比较不同之处子节点更新到DOM编程题项目地址https://github.com/luxiancan/...1.模拟VueRouterhash模式的实现与History模式类似。URL中#后面的内容作为路由的地址,可以通过hashchange事件监听路由地址的变化。答:参考项目./vue-router-lxc,文件路径:./vue-router-lxc/src/vuerouter_hash/index.js2,在模拟Vue.js响应式源码的基础上实现v-html指令代码和v-on指令。答:参考项目./mini-vue-lxc,文件路径:./mini-vue-lxc/js/compiler.js部分代码//处理v-html指令htmlUpdater(node,value,key){node.innerHTML=valuenewWatcher(this.vm,key,newValue=>{node.innerHTML=newValue})}//处理v-on指令onUpdater(node,value,key,eventType){node.addEventListener(eventType,value)newWatcher(this.vm,key,newValue=>{node.removeEventListener(eventType,value)node.addEventListener(eventType,newValue)})}3。参考Snabbdom提供的电影列表的例子,使用Snabbdom实现类似的效果答:参考项目./snabbdom-demo项目文件说明notes:notesmini-vue-lxc:一个小型的vue框架,实现了如responsiveness,interpolationexpressions,andpartialinstructionsvue-router-lxc:基于vue-cli模拟,实现了vue-routerhistory和hashsnabbdom的两种模式-demo:使用snabbdom开发的一个小demo,用于学习巩固基础用法snabbdom*学习笔记Vue.js基础复习基础设施使用newVue({el:'#app',data:{}})使用newVue({data:{},render(h){}}).$mount('#app')lifecyclenewVue()创建一个新的Vue实例beforeCreateinitializationevent&lifecyclecreatedinitializationinject&检查是否指定"el"选项和"template"选项beforeMountmounted创建vm.$el并用它替换el当数据被修改时,触发beforeUpdate虚拟DOM重新渲染并应用更新,调用vm.$时触发updateddestroy()函数,触发beforeDestroydestroyed解除绑定,销毁后销毁子组件和事件监听器Vue语法和概念插值表达式指令计算属性和监听器Class和Style条件渲染/列表渲染表单输入绑定组件插槽插件混入原理mixin深入响应式VueVue-Router在不同构建版本中的原理Hash模式和History模式的区别无论使用哪种方式,都是客户端路由的实现方式。当路径改变时,它不会向服务器发送请求。HashMode形式上的区别:https://music.163.com/#/playl...History模式:https://music.163.com/playlis...Hash模式原理上的区别是基于在锚点上,而onhashchange事件的History模式是基于HTML5中的HistoryAPI,IE10之后才支持history.pushState()。使用history.replaceStateHistory模式需要服务端的支持。在单页应用中,服务器不存在http://www/testurl.com/login这样的地址,会返回找不到页面。服务器应该返回除静态资源之外的单页应用的index.htmlHistory模式-Node.js/*app.js*/constpath=require('path')//引入处理历史模式的模块consthistory=require('connect-history-api-fallback')//importexpressconstexpress=require('express')constapp=express()//注册处理历史模式的中间件应用程序。use(history())//处理静态资源的中间件,网站根目录../webapp.use(express.static(path.join(__dirname,'../web')))//启动服务器,端口为3000app.listen(3000,()=>{console.log('服务器已启动,端口:3000')})历史模式-nginx从官网http://nginx.org/en/download...下载nginx压缩包。解压压缩包到c盘根目录drive,c:nginx-1.18.0文件夹打开命令行,切换到c:nginx-1.18.0nginx目录下相关命令#startstartnginx#restartnginx-sreload#stopnginx-sstopginx.conffileserver{#...位置/{根html;指数指数。html索引.htm;try_files$uri$uri//index.html;}}VueRouter实现原理#后面的Hash模式URL内容作为路径地址,监听hashchange事件根据当前路由地址找到对应的组件,通过history.pushState()方法改变地址重新渲染History模式bar并监听popstate事件。根据当前路由地址找到对应的组件,重新渲染Vue构建版本。Runtime版本:不支持template模板。需要打包时提前编译当前版本大约10K大。程序运行时,将模板转化为渲染函数,模拟Vue.js响应式原理数据驱动数据响应,双向绑定,数据驱动数据响应。修改数据时,视图也会更新,避免繁琐的DOM操作,提高开发效率双向绑定数据变化,视图变化;尝试改变,数据也会改变我们可以使用v-model在表单元素上创建双向数据绑定数据驱动数据驱动是vue最独特的特性之一。在开发过程中,只需要关注数据本身,不需要关心数据是如何渲染到视图上的。响应性的核心原则。Vue2.xObject.defineProperty浏览器兼容IE8及以上(不兼容IE8)Vue3.xProxy直接监听对象,而不是属性,是ES6中新增的,IE不支持它们,性能由浏览器优化。发布-订阅模式和观察者模式发布/订阅模式。完成后,向信号中心“发布”一个信号,其他任务可以“订阅”信号中心,知道什么时候可以开始执行这叫做“发布-订阅模式”(publish-subscribepattern)Vue的自定义事件letvm=newVue()vm.$on('dataChange',()=>{consloe.log('dataChange1')})vm.$on('dataChange',()=>{consloe.log('dataChange2')})vm.$emit('dataChange')兄弟组件通信过程//eventBus.js//事件中心让eventHub=newVue()//ComponentA.vue//PublisheraddTodo:function(){//发布消息(事件)eventHub.$emit('add-todo',{text:this.newTodoText})this.newTodoText=''}//ComponentB.vue//Subscribercreated:function(){//订阅消息(事件)eventHub.$on('add-todo',this.addTodo)}模拟Vue自定义事件的实现classEventEmitter{constructor(){//{'click':[fn1,fn2],'change':[fn]}this.subs=Object.create(null)}$on(eventType,handler){this.subs[eventType]=this.subs[事件类型]||[]this.subs[eventType].push(handler)}$emit(eventType){if(this.subs[eventType]){this.subs[eventType].forEach(handler=>{handler()})}}}观察者模式观察者(订阅者)——Watcherupdate():当事件发生发生时,具体要做的事情Target(publisher)--depsubs数组:存放所有观察者addSub():添加观察者notify():事件发生时,调用所有观察者的update()方法无事件中心总结观察者模式由特定目标调度。比如当一个事件被触发时,Dep会调用观察者的方法,所以观察者模式的订阅者和发布者之间存在依赖的发布/订阅模式。统一调度中心调用,发布者和订阅者不需要知道对方的存在模拟Vue的响应式原理Vue基本结构整体分析打印Vue实例整体结构观察将数据成员注入Vue实例,将数据成员转化为getter/setterObserver:能够监听数据对象的所有属性。如果有任何变化,您可以获取最新的值并通知DepVue。负责接收初始化参数。负责将数据中的属性注入到Vue实例中,转换成getters/setters。负责调用观察者监测数据中所有属性的变化,负责调用编译器解析指令/插值表达式。Observer负责将数据选项中的属性转换为响应式数据。数据中的某个属性也是一个对象,将属性转化为响应式数据。数据更改向负责编译模板的编译器发送通知。解析指令/插值表达式负责页面的首次渲染。当数据改变时,视图被重新渲染。Dep(依赖)收集依赖,添加观察者(watcher)通知所有观察者。当数据变化触发依赖时,dep通知所有Watcher实例更新视图。实例化自己的时候,把自己的总结问题添加到dep对象中,将data中的一个属性重新赋值给一个对象。它有反应吗?---向Vue实例添加成员是否有响应?---没有VirtualDOM的实现原理是什么?为什么使用VirtualDOM手动操作DOM比较麻烦?您还需要考虑浏览器兼容性问题。虽然jQuery等库简化了DOM操作,但是随着项目复杂的DOM操作,为了简化DOM的复杂操作,各种复杂的操作应运而生。MVVM框架,MVVM框架解决了view和state的同步问题。为了简化视图的操作,我们可以使用模板引擎,但是模板引擎并没有解决跟踪状态变化的问题,所以VirtualDOM出现了。VirtualDOM的好处是当状态发生变化时需要立即更新DOM,只需要创建一个虚拟树来描述DOM,VirtualDOM会想办法有效地更新DOM(diff)virtualDOM的作用维护视图和状态之间的关系在复杂视图情况下提高渲染性能除了渲染DOM,还可以实现SSR(Nuxt.js/Next.js)、原生应用(Weex/ReactNative)、小程序(mpvue/uni-app)等。并不是所有情况下都使用虚拟DOM来提升性能,只有在视图比较复杂的情况下,使用虚拟DOM才会提升渲染性能