7 SY Vue 原理 副本 页面编辑错误
目录
1 组件化
注册组件的基本步骤
全局组件和局部组件
为什么组件data必须是函数
2 模板编译
3 渲染过程
4 前端路由
vue-router实现原理:
1 组件化
可以从以下几点进行阐述:
组件化是 Vue.js 中的重要思想,它提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用。任何的应用都会被抽象成一颗组件树:
定义
组件是可复用的 Vue 实例,准确讲它们是VueComponent的实例,继承自Vue。
优点
组件化可以增加代码的复用性、可维护性和可测试性。
使用场景
什么时候使用组件?以下分类可作为参考:
通用组件:实现最基本的功能,具有通用性、复用性,例如按钮组件、输入框组件、布局组件等。
业务组件:它们完成具体业务,具有一定的复用性,例如登录组件、轮播图组件。
页面组件:组织应用各部分独立内容,需要时在不同页面组件间切换,例如列表页、详情页组件
如何使用组件
定义:Vue.component(),components选项,sfc
分类:有状态组件,functional,abstract
通信:props,e m i t ( ) / emit()/emit()/on(),provide/inject,c h i l d r e n / children/children/parent/r o o t / root/root/attrs/$listeners
内容分发:<slot>,<template>,v-slot
使用及优化:is,keep-alive,异步组件
注册组件的基本步骤
Vue.extend()这种写法在Vue2.x以后基本就很少见了,会直接使用语法糖,但内部还是这个原理。
全局组件和局部组件
当我们通过调用 Vue.component()
注册组件时,组件的注册是全局的,这意味着该组件可以在任意 Vue 实例下使用;如果我们注册的组件是挂载在某个实例中, 那么就是一个局部组件
组件的本质
vue中的组件经历如下过程
组件配置 => VueComponent实例 => render() => Virtual DOM=> DOM
所以组件的本质是产生虚拟DOM
为什么组件data必须是函数
组件是一个单独功能模块的封装,这个模块有属于自己的HTML模板。组件对象也有一个 data 属性,只是这个 data属性必须是一个函数,而且这个函数返回一个对象,对象内部保存着数据。
首先,如果不是一个函数,Vue
直接就会报错;其次,Vue
让每个组件对象都返回一个新的对象,因为如果是同一个对象的,组件在多次使用后会相互影响
2 模板编译
vue模板=》render函数=》vnode=》进行patch和diff
对于Vue来说,我们所认为的“HTML”其实都是字符串。
Vue会根据其规定的模板语法规则,将其解析成AST语法树;
然后会对这个大对象进行一些初步处理,比如标记没有动态绑定值的节点;
最后,会把这个大对象编译成render函数,并将它绑定在组件的实例上。
这样,我们所认为的“HTML”就变成了JavaScript代码,可以基于JavaScript模块规则进行导入导出,在需要渲染组件的地方,就调用render函数,根据组件当前的状态生成虚拟dom,然后就可以根据这个虚拟dom去更新视图了。
Vue的模板编译就是将“HTML”模板编译成render函数的过程。这个过程大致可以分成三个阶段:
- 解析阶段:将“HTML”模板解析成AST语法树;
- 优化阶段:从AST语法树中找出静态子树并进行标记(被标记的静态子树在虚拟dom比对时会被忽略,从而提高虚拟dom比对的性能);
- 代码生成阶段:通过AST生成代码字符串,并最终生成render函数。
(注:当前节点及其所有子节点都是静态节点,当前节点才会被打上静态节点的标记)
(注:静态根节点是指本身及所有子节点都是静态节点,但是父节点为动态节点的节点,找到了静态根节点也就找到了“静态子树”)
template = '<div :id="myid">hello,xiang</div>';var compiler = require('vue-template-compiler') compiler.compile(template)返回结果是一个render函数:with(this){return _c('div',{attrs:{"id":myid}},[_v("hello,xiang")])}
_c是createElement 函数,也就是snbbdom中的h函数, _v是createTextVNode
函数会通过“with”语法将this上的属性和数据解析成变量,比如:代码字符串中的_c相当于this._c,name相当于this.name。_c、_v这些变量其实就是vue创建不同类型虚拟dom节点的方法,比如_c就是我们在写render函数时非常熟悉的创建元素类型节点的createElement方法,_v是创建文本类型节点的方法。
前置知识:js的with语法
vue template complier 将模板编译为render函数
执行render函数生成vnode
with语法
改变{}内自由变量的查找规则,当做obj属性来查找
如果找不到匹配的obj属性,就会报错
with要慎用,它打破了作用域规则,易读性变差
模板编译
模板编译为render函数,执行人的人函数返回vnode
基于vnode再执行patch和diff
使用webpack vue-loader,会在开发环境下编译模板(重要)
3 渲染过程
初次渲染过程
解析模板为render函数,开发环境中,vue-loader会做这件事
触发响应式,利用getter和setter监听data属性
首次执行render函数(会触发getter),生成vnode,patch(elem, vnode)
更新过程
修改data,触发setter
重新执行render函数,生成newVnode
patch(vnode,newVnode)
流程图:
组件被 complier 编译成 Render 函数
执行 Render函数 生成 vDom
在 Render 函数中,触发 Data 属性的 getter,并被收集起来(Collect as Dependency)
观察(Watcher) 这些被收集的依赖
修改 Data 属性,setter 去通知(Notify)Watcher
若 Watcher 中存在修改的 Data 属性,则触发(Trigger)re-render
重新执行 Render 函数
异步渲染
汇总data修改,一个事件循环中多次修改会汇总一次性更新试图
减少渲染次数,提高性能
nexttick在渲染完成后执行
4 前端路由
后端路由:
早期传统MVC网站路由都是服务端主导,前端通过不同URL请求后端,后端框架有专门的路由模块用来匹配URL地址,然后根据不同地址和参数调用相关处理程序并返回html页面给前端。
前端路由:
后来前后端分离,react/vue等框架流行,路由由前端主导。还是由前端改变url,但要做到不发生真实的网页跳转,即不向服务器请求网页。然后改由前端监听路由变化,并截获路由进行匹配以显示不同的前端组件,组件再通过ajax获取视图所需json数据。
前端路由分两种:hash模式 和 history模式。
Vue Router sh
hash模式 实现原理
(1) 通过a标签、window.location改变hash。
hash是URL中#及后面的那部分,改变hash会记入历史栈,不会发起页面请求。
(2) 通过hashchange事件监听hash变化,触发页面改变。
a标签跳转、window.location跳转,浏览器前进后退引起的hash变化都可以触发chashchange 事件。
location.hash 获取浏览器的hash值
hashchange 监听浏览器的hash值变化
hash特点:
hash变化会触发网页跳转,就是浏览器的前进、后退
hash变化不会刷新页面,SPA的必备条件
hash不会提交到server端
//这里需要你在html中创建一个id为app的dom用于放置内容
var appNode = document.querySelector("#app");
window.addEventListener("hashchange", () => {Router.hash.handler();
});
var Router = {//list = 路由列表, 模仿vue-router中的routerlist写法, component做了简化只是一段文字;list: [{ path: "/", name: "index", component: "This is index page" },{ path: "/hash", name: "hash", component: "This is hash page" },{ path: "/history", name: "history", component: "This is history page" },{ path: "*", name: "notFound", component: "404 NOT FOUND" }],//输入path:String对应路由列表中的path, 实现渲染功能render: function(path) {var ele = null;//用于存储没有匹配路径时的404内容, 在这里默认路由列表中最后一个元素为404内容var naEle = this.list[this.list.length - 1];//通过path找出路由列表中对应的路由信息this.list.forEach(item => {if (item.path === path) ele = item;});//如果找到了path对应的路由信息, 则返回; 没找到的话, 返回404信息ele = ele ? ele : naEle;//将路由信息中的component加载进根节点appNode.innerHTML = ele.component;},hash: {//渲染handler: function() {Router.render(this.getState());},//获取当前hashgetState: function() {var hash = window.location.hash;hash = hash ? hash.slice(1) : "/";return hash;},getUrl: function(path) {var href = window.location.href;var i = href.indexOf("#");var base = i >= 0 ? href.slice(0, i) : href;return base + "#" + path;},push: function(path) {window.location.hash = path;},replace: function(path) {window.location.replace(this.getUrl(path));},go: function(n) {window.history.go(n);}}
};
//加载初始页面
Router.render(window.location.hash ? window.location.hash.slice(1) : "/");
history的原理是H5的几个新API
history.pushState(data,title,url):在浏览器中新增一条历史记录;
data会在onpopstate事件触发时作为参数传递过去,title为页面标题,url为页面地址;
history.replaceState(data,title,url):在浏览器中替换当前历史记录;
data会在onpopstate事件触发时作为参数传递过去,title为页面标题,url为页面地址;
history.length():当前历史列表中的历史记录条数;
window.onpopstate:实际上popstate是一个浏览器内置的点击事件,响应pushState和replaceState的触发调用;
history.back(-1):返回到当前页的上一页(原页面表单中的内容会保留)
history.back(0):页面刷新
history.back(1):当前页前进一页
history.go(-1): 返回到当前页的上一页(原页面表单中的内容会丢失,效果基本和history.back(-1)一样
history.forward():当前页面前进一页(和history.back(1)效果一样
此外,history方法可以直接调用,例:history.pushState(),也可以用window.history.pushState()来调用。因为history是属于浏览器中的子对象,两种调用方法都是生效的;
var appNode = document.querySelector("#app");
window.addEventListener("popstate", () => {Router.history.handler();
});
var Router = {list: [{ path: "/", name: "index", component: "This is index page" },{ path: "/hash", name: "hash", component: "This is hash page" },{ path: "/history", name: "history", component: "This is history page" },{ path: "*", name: "notFound", component: "404 NOT FOUND" }],render: function(path) {var ele = null;var naEle = this.list[this.list.length - 1];this.list.forEach(item => {if (item.path === path) ele = item;});ele = ele ? ele : naEle;appNode.innerHTML = ele.component;},history: {//渲染handler: function() {Router.render(this.getState());},//获取当前pathgetState: function() {const path = window.location.pathname;return path ? path : '/';},//pushState相关参数说明//状态对象(state object):一个JavaScript对象,与用pushState()方法创建的新历史记录条目关联。无论何时用户导航到新创建的状态,会触发popstate事件,并能在事件中使用该对象。//标题(title):一般浏览器会忽略,最好传入null。//地址(URL):就是需要新增的历史记录的地址,浏览器不会去直接加载改地址,但后面也可能会去尝试加载该地址。此外需要注意的是,传入的URL与当前URL应该是同源的。push: function(path) {window.history.pushState(null, null, path)this.handler()},replace: function(path) {window.history.replaceState(null, null, path)this.handler()},go: function(n) {window.history.go(n);}}
};
//加载初始页面
Router.render(window.location.pathname);
前端路由:原理篇_Palate的博客-CSDN博客_前端路由原理通过这篇文章,你可以了解到:为什么需要前端路由?解决了什么问题?前端路由的基本原理是什么?hash路由的hash值会发送到服务端吗?history路由为什么需要服务端支持?https://blog.csdn.net/weixin_51670675/article/details/124239269?ops_request_misc=&request_id=&biz_id=102&utm_term=%E5%89%8D%E7%AB%AF%E8%B7%AF%E7%94%B1%E7%9A%84%E5%8E%9F%E7%90%86&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-0-124239269.142%5Ev47%5Enew_blog_pos_by_title,201%5Ev3%5Econtrol_2&spm=1018.2226.3001.4187前端路由原理解析(含代码实现)_jim点点点点点的博客-CSDN博客关于前端路由你可能需要知道的内容什么是路由? 前端路由出现之前又是怎么实现路由的?前端路由hash 路由history 路由前端路由的缺点总结写在正文前: 作为一位已经工作了两年的前端 CRUD boy, 整日潜水在论坛看见各位大佬们谈天说地, 表示万分仰慕, 也想加入各位的吹水大军. 为此, 下定决心正式开始写文章锻炼自己的吹水能力, 也希望自己能坚持写下去. 还望各位大佬多多指正, 给小弟一...https://blog.csdn.net/jind325/article/details/105325221?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166291643516800182127497%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=166291643516800182127497&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-2-105325221-null-null.142%5Ev47%5Enew_blog_pos_by_title,201%5Ev3%5Econtrol_2&utm_term=%E5%89%8D%E7%AB%AF%E8%B7%AF%E7%94%B1%E4%BB%A3%E7%A0%81&spm=1018.2226.3001.4187
vue-router实现原理:
SPA(single page application):单一页面应用程序,只有一个完整的页面;它在加载页面时,不会加载整个页面,而是只更新某个指定的容器中内容。单页面应用(SPA)的核心之一是: 更新视图而不重新请求页面;vue-router在实现单页面前端路由时,提供了两种方式:Hash模式和History模式;根据mode参数来决定采用哪一种方式。
方式1:直接修改地址栏
方式2:this.$router.push(‘路由地址’)
方式3: <router-linkto="路由地址"></router-link>
hash 通过window.onhashchange监听
H5 history 通过history.pushState 和 window.onpopstate监听 实现的
H5 history 需要后台支持
两者选择
to B 的系统推荐用hash,简单易用,对url规范不敏感
eg.管理系统(ToB就是在企业业务中,以企业作为服务主体为企业客户提供平台、产品或服务并赚取利润的业务模式,我们也可以把它称之为企业服务。)
to C的系统,可以考虑选择 H5 history,但需要服务端支持
eg.系统需要做SEO 搜索引擎优化
(tTo B 英文为To Business面向企业 , To C为To Customer面向个体消费者)
能选择简单的,就别用复杂的,要考虑成本和收益
7 SY Vue 原理 副本 页面编辑错误相关推荐
- 【Vue原理】Diff - 源码版 之 Diff 流程
写文章不容易,点个赞呗兄弟 专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧 研究基于 Vue版本 [2.5.17] 如果你觉得排版难 ...
- vue 加载页面时触发时间_详解Vue.js在页面加载时执行某个方法
详解Vue.js在页面加载时执行某个方法 jQuery中可以这样写 vue中,如果要达到相同效果,可以使用vue的生命周期函数,如create或者mounted 附上vue.js的生命周期函数执行流程 ...
- Java快速开发平台,JEECG 3.7.5 Vue SPA单页面应用版本发布
JEECG 3.7.5 Vue SPA单页面应用版本发布 导读 ⊙ Vue+ElementUI SPA单页面应用 ⊙Datagrid标签快速切换BootstrapTable列表风 ...
- vue如何创建vnode_【Vue原理】Component - 源码版 之 创建组件VNode
专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧 研究基于 Vue版本[2.5.17] 今天就要开启我们 Component 探索之旅 ...
- element 往node里面增加属性值_【Vue原理】Compile - 源码版 之 Parse 属性解析
写文章不容易,点个赞呗兄弟 专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧 研究基于 Vue版本 [2.5.17] 如果你觉得排版难 ...
- ASP.NET Core 中文文档 第三章 原理(5)错误处理
原文:Error Handling 作者:Steve Smith 翻译:谢炀(Kiler) 校对:高嵩(jack2gs).何镇汐 当你的ASP.NET应用发生错误的时候, 你可以采用本文所述的各种方法 ...
- vue 启动时卡死_十分钟浅入Vue 原理
vue原理 引用 众所周知vue是一个MVVM 渐进式框架,MVVM是vue的设计模式,在vue框架中数据会自动驱动视图. 1.MVVM设计模式 解释 View是视图,就是DOM:对应视图也就是H ...
- vue 数值 拼接字符串_【Vue原理】Compile - 白话版
写文章不容易,点个赞呗兄弟 专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧 研究基于 Vue版本 [2.5.17] 如果你觉得排版难 ...
- v-model双向绑定原理_【Vue原理】VModel 白话版
↑点击上方 "神仙朱" 一起研究Vue源码吧 专注 Vue 源码分享,为了方便大家理解,分为了白话版和 源码版,白话版让大家可以轻松理解工作原理,源码版让大家更清楚内部操作和 Vu ...
最新文章
- 经典模式流水灯实验的个人总结和思考
- mfc程序转化为qt_工控编程,Qt 学习之路
- 更新CentOS Mysql到官方较新版本[以6.5为例]
- Database之SQLSever:SQL命令实现的高级案例集合之单表/多表(筛选、统计个数)之详细攻略
- c语言 遍历.jpg图像,求指导,如何用c语言实现读取*.raw格式图像
- Java多线程相关的几十个问题
- HDU 5763 Another Meaning KMP+DP
- 纳德拉:微软正计划“终极移动设备”
- C#生成图形验证码 (转)
- POJ 2377 Bad Cowtractors
- 谷歌账号 (亲测有效)
- excel换行快捷键_超实用的16个Excel快捷键,一定要收藏!
- Java开发OCR文字识别系统
- mysql数据库安全开关_对MySQL数据库的安全进行的详述
- BAT机器学习面试1000题系列(第1~305题
- 一对一直播源码开发,一对一视频直播解决方案新思路
- Java 链表知识总结
- Zephyr 3.2 弃用devicetree 中node 里的label property
- python数据分析库pandas-三、: python数据分析处理库-Pandas
- 电信云的原理及相关架构
热门文章
- Don Box博客中文版入驻CSDN,志愿者翻译招募中....
- qsort的基本用法
- java Servlet 笔记
- 小感悟:多对多关系,一定要创建关系表吗?
- 自然语言处理NLP 2022年最新综述:An introduction to Deep Learning in Natural Language Processing
- python机器语言直接用二进制代码表达指令_尔雅慕课搜题app,超星尔雅考试搜题,超星慕课查题app,学堂云搜题...
- 回车符,换行符与'\0'
- STM32三菱FX1N,FX2N,FX3U,PLC方案 可以直接上传下载梯形图,在线监控,具有称重功能,数码管功能,可以做到10路模拟量
- JavaScript计算两个日期之间相差的天数
- 《本地计算机DNS缓存文件》