技术总结
2023-12-08 17:32:31 10 举报
AI智能生成
总结是对一段文字、事件或经验的概括和归纳。它通常包括对主要观点、事实或结果的简明扼要的描述,以及对相关信息的整理和梳理。总结的目的是帮助读者快速了解和掌握文本的核心内容,以便更好地理解和应用所学知识。总结应该清晰、简洁、准确地表达主要信息,同时避免冗长和重复。通过总结,读者可以迅速获取关键信息,节省时间和精力,提高学习和工作效率。总结是一种重要的阅读和写作技巧,对于提高思维逻辑和表达能力也非常有帮助。无论是在学术研究、新闻报道还是日常交流中,总结都扮演着重要的角色,帮助我们更好地理解和传递信息。
作者其他创作
大纲/内容
css
1.position:fixed降级问题
如果父元素中有使用transform,fixed的效果会降级为absolute
2.比较小的图案
rem转为px会存在精度丢失问题
画5px的圆,使用rem,会在一些机型上呈椭圆形
一般情况下的rem精度在可接受范围内
3.line-height
建议使用line-height:em,在调整时,只需要修改font-size,line-height就被设置为相对行高
4.首行缩进两个单位
text-indent:2em
5.以rem单位设计的弹性布局,是需要在头部加载一段脚本来进行监听分辨率的变化来改变根元素字体大小,使得css和js耦合在了一起
采用视口单位vw|vh
6.内联首屏关键css
性能优化中的重要指标,首次有效绘制,即指页面的首要内容出现在屏幕上的时间,这一指标影响用户看到页面前所需等待的时间
内联首屏关键 CSS(即 Critical CSS,可以称之为首屏关键 CSS) 能给用户一个更好的心理预期。
内联 CSS 能够使浏览器开始页面渲染的时间提前,即在 HTML 下载完成之后就能渲染了。
既然是内联关键 CSS,也就说明我们只会将少部分的 CSS 代码直接写入 HTML 中。
7.-webkit-box-orient: vertical 在使用 webpack 打包的时候这段代码会被删除掉,原因是 optimize-css-assets-webpack-plugin 这个插件的问题。
8.div默认宽度是父元素宽的100%
9.逐帧动画 animation :animate-name 3s steps(每次循环的次数) infinite
10.行内元素与下一个元素中间有空格(正常排版),会引起一些诡异的缝隙,常见的例如元素之间有间隔,或看起来空了一行(像加了padding)
大概4px左右缝隙,可以用font-size:0解决
11.移动端优化常见css属性
1.user-select:none
禁止文字被选中
2.outline:none
点击去除外边框,点击无轮廓
3.-webkit-touch-callout: none
长按链接不弹出菜单
4.-webkit-tap-highlight-color: rgba(0,0,0,0)
去除点击高亮
12.@keyframes 的属性要前后对应,否则不形成动画
13.img 元素图像自适应居中,与 background-size 效果一样
object-fit: cover;
14. 标签千万记得写宽高,不然会花式塌陷
15.flex-grow 所在元素如果未定宽度的话,宽度会被子元素撑开
16.一个英文单词默认不换行,无论多长,所以要设置 word break
17.safari 中控制惯性滚动 -webkit-overflow-scroll
18.flex 布局不换行加 flex-shrink: 0; 实现 div 不压缩无限并排,可以用于 swiper 等场景。
19.float 自带 display: inline-block
20.鼠标禁用 .disabled { pointer-events: none; }
21.::after 表示法是在 CSS3 中引入的,:: 符号是用来区分伪类和伪元素的。支持CSS3的浏览器同时也都支持 CSS2 中引入的表示法 :after。
22.vh 在部分浏览器中包含地址栏部分,小心使用。
关于设计模式
六大原则
1.开闭原则
1.定义:一个软件实体应当对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。
2.实现
1.关键点
抽象化是开闭原则的关键,为了满足开闭原则,需要对系统进行抽象化设计。抽象化是开闭原则的关键
2.主流实现方式
在很多面向对象编程语言中都提供了接口、抽象类等机制,可以通过它们定义系统的抽象层,再通过具体类来进行扩展。如果需要修改系统的行为,无须对抽象层进行任何改动,只需要增加新的具体类来实现新的业务功能即可,实现在不修改已有代码的基础上扩展系统的功能
eg:在Java、C#等编程语言中,可以为系统定义一个相对稳定的抽象层,而将不同的实现行为移至具体的实现层中完成
3.优点:
1.实践开闭原则的优点在于可以在不改动原有代码的前提下给程序扩展功能。增加了程序的可扩展性,同时也降低了程序的维护成本
2.里氏替换原则
所有引用基类对象的地方能够透明地使用其子类的对象
3.依赖倒置原则
抽象不应该依赖于具体类,具体类应当依赖于抽象。换言之,要针对接口编程,而不是针对实现编程。
4.单一职责原则
一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因。
5.迪米特法则(最少知道法则)
一个软件实体应当尽可能少地与其他实体发生相互作用
6.接口分离原则
使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。
设计模式
1.创建型设计模式
1.定义
创建型模式(Creational Pattern)对类的实例化过程进行了抽象,能够将模块中对象的创建和对象的使用分离。为了使结构更加清晰,外界对于这些对象只需要知道它们共同的接口,而不清楚其具体的实现细节,使整个系统的设计更加符合单一职责原则。
2.关注方向
用于创建对象,关注对象的封装和分离,其他对象不需要知道新建对象的内部实现,只需要知道这些对象的共同接口
3.模式种类
1.简单工厂模式
2.工厂方法模式
3.抽象工厂模式
4.单例模式
5.生成器模式
1.定义
生成器模式(Builder Pattern):也叫创建者模式,它将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
2.场景
3.实现
生成器模式将复杂的创建逻辑进行分割,如果创建逻辑简单则没有拆分的必要。
eg:
4.优点
5.缺点
6.原型模式
2.结构型设计模式
1.定义
结构型模式(Structural Pattern)描述如何将类或者对 象结合在一起形成更大的结构,就像搭积木,可以通过 简单积木的组合形成复杂的、功能更为强大的结构。结构型模式可以分为类结构型模式和对象结构型模式
2.关注方向
用于对象间的合成,关注对象间的关联关系,用于描述如何将类或者对象结合在一起形成更大的结构
1.类结构
关心类的组合,由多个类可以组合成一个更大的系统,在类结构型模式中一般只存在继承关系和实现关系。
2.对象型结构
关心类与对象的组合,通过关联关系使得在一 个类中定义另一个类的实例对象,然后通过该对象调用其方法。 根据“合成复用原则”,在系统中尽量使用关联关系来替代继 承关系,因此大部分结构型模式都是对象结构型模式。
2.模式种类
1.装饰模式
2.外观模式
3.代理模式
4.享元模式
5.桥接模式
6.适配器模式
3.行为型设计模式
1.定义
行为型模式(Behavioral Pattern)是对在不同的对象之间划分责任和算法的抽象化。行为型模式不仅仅关注类和对象的结构,而且重点关注它们之间的相互作用。通过行为型模式,可以更加清晰地划分类与对象的职责,并研究系统在运行时实例对象之间的交互。
2.关注方向
用于不同对象间的责任划分和算法抽象,不仅关注对象间的结构,重点关注于对象间的相互作用,研究运行时对象间的交互
2.模式种类
1.职责链模式
2.命令模式
3.解释器模式
4.迭代器模式
1.定义
提供一种方法来访问聚合对象,而不用暴露这个对象的内部表示,其别名为游标(Cursor)。迭代器模式是一种对象行为型模式。
2.场景
1.访问一个聚合对象的内容而无须暴露它的内部表示。
2.需要为聚合对象提供多种遍历方式。
3.为遍历不同的聚合结构提供一个统一的接口。
3.实现
4.优点
1.它支持以不同的方式遍历一个聚合对象,在同一个聚合对象上可以定义多种遍历方式。在迭代器模式中只需要用一个不同的迭代器来替换原有迭代器即可改变遍历算法,我们也可以自己定义迭代器的子类以支持新的遍历方式。
2.迭代器简化了聚合类。由于引入了迭代器,在原有的聚合对象中不需要再自行提供数据遍历等方法,这样可以简化聚合类的设计。
3.在迭代器模式中,由于引入了抽象层,增加新的聚合类和迭代器类都很方便,无须修改原有代码,满足“开闭原则”的要求。
5.缺点
1.由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性
2.抽象迭代器的设计难度较大,需要充分考虑到系统将来的扩展,在自定义迭代器时,创建一个考虑全面的抽象迭代器并不是件很容易的事情。
5.中介者模式
6.备忘录模式
7.观察者模式
8.状态模式
9.策略模式
10.模板方法模式
11.访问者模式
工程化
请求数据
ajax
fetch
axios
axios特征
1.从浏览器中创建XMLHttpRequest
2.从node.js发出http请求
3.支持PromiseAPI
4.拦截请求和响应
5.取消请求
6.自动转换JSON数据
axios的使用举例
1.执行GET请求
1.query
axios.get('/user/ID=12345')
.then((res)=>{console.log(res)}
.catch((err)=>{console.log(err)})
2.通过params传参数
axios.get('/user',{
params:{
ID:12345}
})
.then((res)=>{console.log(res)})
.catch((err)=>{console.log(err)})
2.执行post请求
axios.post('/user',{
ID1:12345,
ID2:123456
})
.then(function(res){console.log(res)})
.catch((err)=>{console.log(err)})
3.执行多个并发请求
function getUserAccount(){
return axios.get('/user/12345')
}
function getUserPermission(){
return axios.get('/user/12345/permissions')}
axios.all([getUserAccount(),getUserPermission()])
.then(axios.spread((account,permission)=>{
console.log(account,permission)}))
axios的相关配置
1.创建
eg:const service =axios.create({//配置项})
2.baseURL
baseURL属性是请求地址前缀,将自动加在url前面,除非url是绝对地址
正常情况下开发模式和生产模式下有着不同的baseURL,所以需要根据不同
切换不同的baseURL
3.统一设置请求头
跨域
1.postmessage
前端安全
1.xss
2.csrf
3.SQL注入
几种功能性插件与浏览器API
1.复制功能 clipboard
1.说明:clipboard.js是一款轻量级的实现复制文本到剪贴板功能的JavaScript插件。通过该插件可以将输入框,文本域,DIV元素中的文本等文本内容复制到剪贴板中,它是一种一个不需要flash,将文本复制到剪贴板的插件
2.clipboard复印内容的方式
1.从target复制目标内容
几种属性
1.data-clipboard-target指向复印节点
eg:
Copy
2.data-clipboard-action到剪贴板的方式,两种取值:copy--复制,cut--剪切(cut只能在input和textare中起作用)
3.data-clipboard-text属性返回复印的内容
2.通过function 要复印的内容
1.target
通过target的function复印内容
通过target指定要复印的节点
例子复制的是hello
eg:Copy_target
hello
var clipboard = new Clipboard('.btn', {
// 通过target指定要复印的节点
target: function() {
return document.querySelector('div');
}
});
clipboard.on('success', function(e) {
console.log(e);
});
clipboard.on('error', function(e) {
console.log(e);
});
2.text
通过text的function复印内容
text的function指定的复印内容
例子复制的是to be or not to be
eg:Copy
var clipboard = new Clipboard('.btn', {
// 点击copy按钮,直接通过text直接返回复印的内容
text: function() {
return 'to be or not to be';
}
});
clipboard.on('success', function(e) {
console.log(e);
});
clipboard.on('error', function(e) {
console.log(e);
});
3.通过属性返回复印的内容
返回值的内容是data-clipboard-text的内容
1.单节点示例
// 通过id获取复制data-clipboard-text的内容
Copy
var btn = document.getElementById('btn');
var clipboard = new Clipboard(btn);
clipboard.on('success', function(e) {
console.log(e);
});
clipboard.on('error', function(e) {
console.log(e);
});
2.多节点示例(例中每个按钮被点击时,会复制对应节点的data-clipboard-text的值)
// 通过class注册多个button,获取data-clipboard-text的值
Copy
Copy
Copy
var clipboard = new Clipboard('.btn');
clipboard.on('success', function(e) {
console.log(e);
});
clipboard.on('error', function(e) {
console.log(e);
});
3.clipboard.destroy()
释放内存
4.移动端clipboard失效
1.产生原因
因为移动端项目为了防止用户长按文本实现复制,一般在重置reset.css里面都会设置
导致这些节点无法被选中
div, p, a, ul, li, ol, h1, h2, h3, h4, h5, h6, span {
-webkit-user-select: none;
-webkit-touch-callout: none;
}
2.解决方法
1.通过css
设置节点可以被选中
user-select:auto
缺点:用户长按文本也能实现复制
2.通过js
通过function实现方式指定对应的text
eg:this.clip = new ClipboardJS('.copy-btn', {
text: () => myInvitedCode ? myInvitedCode : '' //设置text的值,即为需要复制到用户剪贴板的内容
});
3.注意事项
用户点击的部分需要用button标签,我一开始用的div,浏览器调试的时候可以点击,但是在手机上调试时不能实现复制
2.上传下载模板功能
1.URL.createObjectURL()
1.静态方法会创建一个 DOMString,其中包含一个表示参数中给出的对象的URL。这个 URL 的生命周期和创建它的窗口中的 document 绑定。这个新的URL 对象表示指定的 File 对象或 Blob 对象。
1.file对象
提供对文件属性的访问.
2.blob对象
代表二进制类型的大对象,通俗点说,就是Blob对象是二进制数据,但它是类似文件对象的二进制数据,因此可以像操作File对象一样操作Blob对象,实际上,File继承自Blob。
2.通过URL.createObjectURL(blob)可以获取当前文件的一个内存URL
3.执行时机
createObjectURL是同步执行(立即的)
4.优点:使用createObjectURL可以节省性能并更快速,只不过需要在不使用的情况下手动释放内存
2.FileReader.readAsDataURL(file)
1.通过FileReader.readAsDataURL(file)可以获取一段data:base64的字符串
2.FileReader.readAsDataURL是异步执行(过一段时间)
3.优点:如果不太在意设备性能问题,并想获取图片的base64,则推荐使用FileReader.readAsDataURL
3.a标签的download属性
download 属性规定被下载的超链接目标。
在 标签中必须设置 href 属性。
该属性也可以设置一个值来规定下载文件的名称。所允许的值没有限制,浏览器将自动检测正确的文件扩展名并添加到文件 (.img, .pdf, .txt, .html, 等等)。
3.生成二维码功能VueQrcode
1.VueQrcode是一个可以用于生成二维码的vue组件(是组件不是插件---类似于router的那种组件)
2.api
分支主题
4.生成条形码功能VueBarcode
1.VueBarcode是一个可以用于生成二维码的vue组件(是组件不是插件---类似于router的那种组件)
2.参数
format: "CODE39",//选择要使用的条形码类型
width:3,//设置条之间的宽度
height:100,//高度
displayValue:true,//是否在条形码下方显示文字
text:"456",//覆盖显示的文本
fontOptions:"bold italic",//使文字加粗体或变斜体
font:"fantasy",//设置文本的字体
textAlign:"left",//设置文本的水平对齐方式
textPosition:"top",//设置文本的垂直位置
textMargin:5,//设置条形码和文本之间的间距
fontSize:15,//设置文本的大小
background:"#eee",//设置条形码的背景
lineColor:"#2196f3",//设置条和文本的颜色。
margin:15//设置条形码周围的空白边距A版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/dakache11/article/details/83749410
5.右键弹出菜单功能
分支主题
6.navigator.userAgent
window上的,用于判断当前运行的浏览器
7.process.env属性返回的是一个包含用户环境信息的对象,它可以区分开发环境或正式环境的依据
vue相关
store相关
1.require.context
require.context妙用-实现前端自动引入同一文件夹下多个文件(替代import)
1.场景:我们的vuex可以分出很多个子模块,也就是子modules,类似于子组件,子模块也需要我们抽离出去,使用导入就可以达到使用效果
但是如果抽离的modules很多,一个一个的导入到store里面是不是很麻烦
分支主题
相当于
分支主题
2.用法
1.例子
分支主题
2.参数
1.directory:要搜索的目录, 2.是否搜索其子目录, 3.匹配文件的正则表达式
2.Vuex持久化插件(vuex-persistedstate)-解决刷新数据消失的问题
1.场景:vuex定义全局状态,在F5刷新页面后,vuex会重新更新state,所以,存储的数据会丢失。我们可以结合本地存储(localstorage等)做到数据持久化,也可以通过插件-vuex-persistedstate。
2.作用:插件的原理其实也是结合了存储方式,只是统一的配置就不需要手动每次都写存储方法,就是不用我们手动存放本地存储,插件自动存储
3.用法:
分支主题
可以设置成sessionstorage
分支主题
指定需要持久化的state/(没有则全部缓存)
分支主题
引入插件,如果不设置的话默认将vuex存储到localstorage
3.namespaced
1.作用
vuex中的store分模块管理,需要在store的index.js中引入各个模块,为了解决不同模块命名冲突的问题,将不同模块的namespaced:true,之后在不同页面中引入getter、actions、mutations时,需要加上所属的模块名
2.声明分模块的store时加上namespaced:true
分支主题
3.使用模块中的mutations、getters、actions时候,要加上模块名
分支主题
4.namespaced表示当前模块是否使用命名空间,如果使用的话,那么设置了namespaced属性的模块将和其它模块独立开来,调用时得指定命名空间后才可以访问得到
v-directive自定义指令构造器
1.全局指令:
如果我们想将一个指令注册为全局指令的话,我们可以将代码写到main.js里面,或者新建一个index.js文件,然后在main.js里面import引入,再use()一下,不过要注意注册为全局变量的话代码需要改变一下
写法: Vue.directive('指令名',{bind:function{el,{binding},Vnode}{})
el:真实dom节点,打印el可以出现此指令所在的dom节点
Vnode:Vue编译出的虚拟节点
bingding:一个对象,它包含了:
name:指令名,不包括 v- 前缀
value: 指令绑定的值,例如:v-count="1 + 1"中,绑定值为 2
expression: 字符串形式的指令表达式。例如:v-count="1 + 1"中,表达式 为 1 + 1
oldValue: 指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
arg:` 传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 “foo”
modifiers: 一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为{ foo: true, bar: true }
eg:Vue.directive('premission',{bind:{function(el,{value}){console.log(el)}
使用时类似于v-bind,自定义指令为:v-指令名
2.局部指令:
如果局部使用v-directive
export default{directive:'方法名':{bind:function(el){},insert:function(){}}
3.钩子函数
1.bind: 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。
2.inserted: 被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。
3.update: 被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新(详细的钩子函数参数见下)。
4.componentUpdated: 被绑定元素所在模板完成一次更新周期时调用。
5.unbind: 只调用一次, 指令与元素解绑时调用。
分支主题
decodeURIComponent:对url解码
replace: true只是一个设置信息,告诉VUE本次操作后,不能通过浏览器后退按钮,返回前一个路由。
不希望用户在addRoutes()还没有完成的时候,可以点击浏览器回退按钮搞事情吧。
组件间通信
1.provide和inject
祖先组件和孙子组件传值
在父组件中使用provide,子组件接收使用inject
用法1
父组件:
provide:{
for:'demo'
}
子组件:inject:['for']
无法传递组件中的变量
用法2
父组件:
provide(){
return {
parent:this
}
以方法的形式传递的原因,在组件中使用provide,如果不是方法的话,拿不到组件的this
缺陷:无法传递响应式的数据
用法3
provide() {
return {
exportGoodsTypeMap: this.exportGoodsType,
getExportGoodsType: () => {
return this.exportGoodsType
}
}
},
子组件:{
inject: ['exportGoodsTypeMap', 'getExportGoodsType'],
computed: {
exportGoodsType() {
return this.getExportGoodsType()
}
}
}
这里不论子组件有多深,只要调用了inject那么就可以注入provider中的数据。而不是局限于只能从当前父组件的prop属性来获取数据
vue.js官方文档(vue2)
1.全局配置
vue.config是一个对象,包含vue的全局配置,可以在启动应用之前修改以下property
silent
slient是boolean类型的值,默认值是false,用于控制vue的日志和警告
vue源码
1.开头
1.封装了很多常用的函数
eg:常见的类型判断、类型转换、数据格式转换(数组转对象)
eg
function isObject(obj) { return obj !== null && typeof obj === 'object'}
function isUndef(v) { return v === undefined || v === null}
function isDef(v) { return v !== undefined && v !== null}
function toString(val) {
return val == null ? '' :
typeof val === 'object' ?
JSON.stringify(val, null, 2) : String(val)
}
function toObject(arr) {
var res = {};
for (var i = 0; i < arr.length; i++) {
if (arr[i]) {
extend(res, arr[i]);
}
} return res
}
节点操作兼容函数
function addClass(el, cls) {
if (!cls || !(cls = cls.trim())) return
if (el.classList) {
if (cls.indexOf(' ') > -1) {
cls.split(/\s+/).forEach(function(c) { return el.classList.add(c); });
} else {
el.classList.add(cls);
}
} else {
var cur = " " + (el.getAttribute('class') || '') + " ";
if (cur.indexOf(' ' + cls + ' ') < 0) {
el.setAttribute('class', (cur + cls).trim());
}
}
}
2.用到了很多设计模式
观察者模式、状态模式、节流模式、
参与者模式、备忘录模式、单例模式
装饰者模式、组合继承模式、链模式
参与者模式、备忘录模式、单例模式
装饰者模式、组合继承模式、链模式
eg:makeMap
创建 对象 map,返回函数,用于后面查找 某个东西是否存在 map 中
function makeMap( str, expectsLowerCase ) {
var map = Object.create(null);
var list = str.split(',');
for (var i = 0; i < list.length; i++) {
map[list[i]] = true;
}
return expectsLowerCase ?
function(val) { return map[val.toLowerCase()]; } :
function(val) { return map[val]; }
}
// 应用
var isUnaryTag = makeMap(
'area,base,br,col,embed,frame,hr,img,input,isindex,keygen,' +
'link,meta,param,source,track,wbr');
// 查找 area 标签是否存在 上面保存过的 字符串中
isUnaryTag('area')
var map = Object.create(null);
var list = str.split(',');
for (var i = 0; i < list.length; i++) {
map[list[i]] = true;
}
return expectsLowerCase ?
function(val) { return map[val.toLowerCase()]; } :
function(val) { return map[val]; }
}
// 应用
var isUnaryTag = makeMap(
'area,base,br,col,embed,frame,hr,img,input,isindex,keygen,' +
'link,meta,param,source,track,wbr');
// 查找 area 标签是否存在 上面保存过的 字符串中
isUnaryTag('area')
3.使用很多闭包
1、解析组件模板 使用了闭包作为缓存,为了重复解析
2、cached 函数,一个专门使用闭包 为缓存的函数
3、上面所讲到 的 柯里化所有涉及的函数,makeMap,parthPath,
4、createPatchFunction 当属篇幅最大的使用闭包的函数了,把一堆函数作为闭包,然后返回 一个函数。他最大的作用是 比较更新DOM 节点
4.使用很多标志位
1.表明已经做了某件事
_isMounted:dom 是否已经挂载
_isDestroyed :组件是否已经摧毁
pending:表明更新回调的 setTimeout 已经执行
waiting:是否已经初始化更新队列,在等待新的成员进入对垒
flushing:更新队列是否已经开始逐个更新成员
2.指明当前东西的身份
isStatic:是否是静态节点
isComment:是否是注释节点
isCloned:是否是克隆节点
isOnce:是否有v-once 指令(如果有当前指令,会跳过编译)
_isComponent:是否是组件
2、Vue
1、vue主体内容
1、依赖收集
2、依赖更新
3、VirtualDOM、dom节点、生成虚拟Vnode节点
4、Compile、模板编译
5、DIff、Patch、节点比较更新
6、NextTick、延迟执行回调
7、Render、渲染机制
8、LifeCircle、生命周期
9、Model、双向绑定
10、Event、事件机制
2、Vue组件选项
1、computed
2、filter
3、minxin
4、directive
5、slot
6、props
7、watch
vue的函数式组件
1.hookEvent监听组件生命周期
1.内部监听生命周期函数
在Vue的组件中,可以用$on,$once去监听所有的生命周期钩子函数
JSX
1.用JSX代替vue的createElement,也就是h函数
2.用法
1.注意事项:
在JSX中,唯一可以使用的指令就是v-show,除此之外,其他指令都是不可以使用的
指令只是Vue在模板代码里面提高的语法糖,这些语法糖用Js可以代替了
2.指令监听
v-model
v-model是vue的一个语法糖,本质是由value属性(默认)+ input事件(默认)组成。所以在JSX中需要回归本子,通过传递value属性并监听input事件来双向绑定
eg:export default {
data() {
return {
name: ''
}
},
methods: {
// 监听 onInput 事件进行赋值操作
$_handleInput(e) {
this.name = e.target.value
}
},
render() {
// 传递 value 属性 并监听 onInput事件
return
}
}
在新脚手架vue-cli4中,已经默认集成了对v-model的支持,可以直接使用,不用脚手架4的话也可以使用babel-plugin-jsx-v-model来支持
v-if和v-for
在模板代码中,我们可以通过v-for遍历元素,通过v-if判断元素是否渲染,在jsx中,可以使用for循环,array.map来代替,对于v-if,可以使用if语句,三元表达式等来代替
1.循环遍历列表
eg: const list = ['java', 'c++', 'javascript', 'c#', 'php']
return (
{list.map(item => {
return {item}
})}
)
return (
{list.map(item => {
return {item}
})}
)
2.使用条件判断
const isGirl = false
return isGirl ? if : else
v-bind
在模板代码中,我们一般使用v-bind:prop="value"或 :prop="value"来给组件绑定属性,在JSX中的写法类似
eg:render(){
return
}
v-html和v-text
vue中的属性应该有三种,props,attrs,domprops, 在vue中domprops主要包含三个,innerHTML,textContent/innerText,value
v-html:
在vue中用v-html指令来更新元素的innerHTML内容,在JSX里面,要操纵组件的InnerHTML,就需要domprops
eg:export default {
data() {
return {
content: '内容'
}
},
render() {
// v-html 指令在JSX的写法是 domPropsInnerHTML
return
}
}
v-text:
v-text在JSX中的写法是domPropsInnerText
export default {
data() {
return {
content: '内容'
}
},
render() {
return
}
}
实际上我们不需要使用dompropsInnerText,而是将文本作为元素的子节点去使用即可,只有innerHTML才需要使用domPropsInnerHTML写法
{this.content}
.sync
在JSX中.sync也需要属性+事件来实现,
eg:export default {
methods: {
$_handleChangeVisible(value) {
this.visible = value
}
},
render() {
return (
)
}
}
4.事件监听
当我们开发一个组件之后,一般通过this.$emit('change')的方式对外暴露事件,然后通过v-on:change的方式去监听事件,但是,在JSX中无法使用v-on指令。
事件
在JSX中,通过on+事件名称的大驼峰的写法来监听
eg:事件icon-click,在JSX中写为onIconClick
原生事件
监听原生事件时会用到,native修饰符,修饰符也有替代方案,.native可以用nativeOn来代替
eg:监听下拉框根元素的click事件
render(){
return
}
其他事件修饰符
和指令一样,除了个别修饰符以外,大部分的事件修饰符都无法在JSX中使用
.prevent
阻止默认行为
在Jsx中使用event.preventDefault()代替
.self
只当事件是从侦听器绑定的元素本身触发时才会触发回调
使用条件判断来代替
if(event.target !== event.currentTarget){
return
}
.stop
阻止事件冒泡
在jsx中使用event.stopPropagation()代替
.enter和.keyCode
在特定键触发时才触发回调
eg:if(event.keyCode){
}
除了以上修饰符以外,vue做了一些优化,对于.once,.capture,.passive,.capture.once, vue提供了前缀语法帮助我们简化代码
render(){
return (
)
}
分支主题
webpack
1.NODE_ENV
1.在Node中,有全局变量process表示的是当前的node进程
分支主题
2.process.env中包含着关于系统环境的信息。但是process.env中并不存在NODE_ENV这个东西
3.NODE_ENV是用户一个自定义的变量,在webpack中它的用途是判断生产环境和开发环境的依据的
webpack
1.webpack基本流程
1.初始化 npm init -y
2.使用node安装webpack
npm i webpack webpack-cli -D
分支主题
前端权限控制
1.RBAC模型
1.是什么
1.RBAC(Role-Based AccessControl,基于角色的访问控制),就是用户通过角色与权限进行关联。简单地说,一个用户拥有若干角色,每一个角色拥有若干权限。这样,就构造成“用户-角色-权限”的授权模型。
不能直接为用户分配权限,用户权限只能由角色继承而来
分支主题
2.角色是什么
一定数量的权限的集合,权限的载体
3.用户与角色之间,角色与权限之间,一般者是多对多的关系
2.实现思路:
为一个角色赋予一定的权限,如果用户需要使用到该角色旗下的权限,就可以给用户赋予该角色
eg:收银员负责收钱,拥有开单收银、查看订单、查看会员等功能,
库管员负责仓库的管理,拥有商品入库,商品盘点,发货等功能。
一个员工既可以是收银员,也可以是库管员
分支主题
3.用户组
1.为什么使用用户组
当用户的数量非常大时,要给系统每个用户逐一授权(授角色),是件非常烦琐的事情。这时,就需要给用户分组,每个用户组内有多个用户。除了可给用户授权外,还可以给用户组授权。这样一来,用户拥有的所有权限,就是用户个人拥有的权限与该用户所在用户组拥有的权限之和。
分支主题
4.资源模型
1.作用
在应用系统中,权限表现成什么?对功能模块的操作,对上传文件的删改,菜单的访问,甚至页面上某个按钮、某个图片的可见性控制,都可属于权限的范畴。有些权限设计,会把功能操作作为一类,而把文件、菜单、页面元素等作为另一类,这样构成“用户-角色-权限-资源”的授权模型。而在做数据表建模时,可把功能操作和资源统一管理,也就是都直接与权限表进行关联,这样可能更具便捷性和易扩展性
其实就是将权限进行分类管理,放在权限表中
2.权限表
分支主题
权限表中有一列“权限类型”,我们根据它的取值来区分是哪一类权限,如“MENU”表示菜单的访问权限、“OPERATION”表示功能模块的操作权限、“FILE”表示文件的修改权限、“ELEMENT”表示页面元素的可见性控制等。
3.权限表一般是后端做的事情,前端只需要拿到,项目中前端拿到权限表数据之后放在了vuex中,存放到了localstorage
2.前端权限控制
1.后端才是权限的主体,前端能做的权限并不多
从根本上讲前端仅仅只是视图层的展示, 权限的核⼼是在于服务器中的数据变化, 所以后端才是权限的关键, 后端权限可以控制某个⽤户是否能够查询数据, 是否能够修改数据等操作
前端权限的控制本质上来说, 就是控制前端的 视图层的展示和前端所发送的请求
2.后端怎么知道请求是哪个用户发来的
1.cookie
2.session
3.token
1.为什么要将token放在请求头中
放在 header 里面,方便配置请求的中间件,比如用 axios 的 interceptor。请求业务的时候就不需要管理 token。如果 token 验证失败,中间件可以直接请求刷新 token、自动继续原有的请求,而业务接口对这是完全不知情的。如果不这么做,每个接口都需要专门处理 token 失败的 case、刷新 token 后重新请求自己,最终你也会想封装出来的。所以用 header 不仅是约定俗成,是真的解决问题。
请求头可以跨域,cookie不行
现在的项目,请求大多是json的,
后台通过切面也可以做到统一拦截
header中放入token在请求时https的情况下保证了安全性,如果放入参数中,别人就可以获取走你的token,从而有机会破解你的token令牌,你可以想象一下,别人拿到你的token令牌破解了你的用户名和密码后用你的身份做的事情,你就知道为什么要放在header里了。
3.前端的几种权限
1.接口权限
登录完拿到Token,将token存起来(cookie或者ssessionStorage),每次登录的时候头部携带token就行了(axios请求拦截器实现)。
2.按钮权限
我们提前和后端约定好按钮的名字,后端会返回一个按钮权限列表。然后我们根据权限列表使用v-if指令或者 绑定disabled属性达到相应权限效果。
当然更好的最好是自己写一个自定义权限指令,实质就是根据相应权限操作dom
3.页面权限(菜单权限)
个人认为页面权限实际上就是菜单权限,如果说我们没有去某个页面的导航菜单,实际上就是没有去那个页面的权限了,所以说页面权限的实际就是菜单权限。
4.路由权限
菜单权限虽然做到能看不见菜单,但是我可以通过直接输入url的方式去没有权限的页面呀,这种情况需要靠我们的路由权限来阻止。
第一种,先注册好所有的路由,然后获取有资格访问的路由权限列表,最后直接通过Router.beforeEach来判断,每次跳路由的时候判断是否在权限列表里,在的话就放行,不在就提示权限不够
优点:简单暴力,不会跳到404页面(因为去的路由能在路由规则里找到)
缺点:由于初始化了所有路由,运行的时候会挂载不必要的路由(?有待考究)
第二种,先只注册基本路由,然后获取路由权限列表,然后借助route.add() API根据权限列表将有权限的路由动态注册到路由规则上
优缺点与第一种正好相反
replace: true只是一个设置信息,告诉VUE本次操作后,不能通过浏览器后退按钮,返回前一个路由。
不希望用户在addRoutes()还没有完成的时候,可以点击浏览器回退按钮
前端性能优化
1.dom性能瓶颈及其产生的原因
1.dom和sax
1.dom和sax是什么
1.dom
dom是w3c指定的一套规范标准,核心是按树形结构处理数据,dom解析器读入xml文件并在内存中建立一个结构一模一样的“树”,这树各节点和xml各标记对应,通过操纵此“树”来处理xml中的文件。xml文件很大时,建立的“树”也会大,所以会大量占用内存。
DOM是以层次结构组织的节点或信息片断的集合。
2.sax
sax解析器占内存少,效率高。
sax解析器核心是事件处理机制。例如解析器发现一个标记的开始标记时,将所发现的数据会封装为一个标记开始事件,并把这个报告给事件处理器,事件处理器再调用方法(startElement)处理发现的数据。事件处理器可以自己编写也可以从父类继承。
2.dom vs sax
1.dom解析
DOM解析原理:一次性把xml文档加载进内存,然后在内存中构建Document树。
对内存要求比较高。
优点: 对文档crud比较方便(crud 增删改查)
缺点: 不适合读取大容量的xml文件,容易导致内存溢出。
2.sax解析
2.vue 大数据table解决方案
1.问题
1.一直以来从事vue开发要不就是使用element-ui ,要不然就是iview。而在我们的开发中table组件可以说是重中之重,非常频繁的使用到。但是如果碰到数据量多的时候,这个组件的性能非常堪忧。
2.优化思路
1.表格数据使用Object.freeze(data)处理,因为一般来说表格中的数据是不会进行更改的。一般进行更改后都是重新调用接口来重刷一遍数据。这样,vue不会做getter和setter的转换,即这个数据不是响应式的了,可以提高表格渲染的性能。
2.减少使用计算属性和dom的判断渲染。有时候后端只会传给你一个状态码, 你会通过不同的状态码来渲染不同的东西, 比如{status: 0}, 这时候你将要渲染会员这个中文。这时候 你可以在js中先将数据进行转换下,变成{status: '会员'},直接渲染上去。
3.对低版本的element-ui进行版本升级,在element-ui 2.8.0版本中, 对表格的性能进行了提升。
4.分批次渲染
js是单线程,但是使用setTimeout和setInterval可以达到相同的效果
eg:一次渲染10万条数据会造成页面加载速度缓慢,那么我们可以不要一次性渲染这么多数据,而是分批次渲染可以分批次进行渲染,分10次渲染,每一次渲染1000条
在其他语言中使用多线程可以很好的达到效果
插件
1.pl-table
1.要解决的问题
el-table渲染万级以上数据卡顿,因为数据量过多导致浏览器渲染过多的标签元素 导致DOM树占用内存较大 使得用户操作阻塞。
2.使用上:
pl-table基于el-table,所以继承了el-table组件的所有方法
只需要把所有带el-table开头的标签改为pl-table开头 并加入use-virtual 属性
设置了use-virtual就是给列表设置虚拟滚动
2.umy-ui
1.umy-ui跟pl-table的作用类似
都是用于解决el-tabke数据量过多导致操作卡顿问题
2.和el-table兼容使用
使用element-ui中的table组件,在外层用u-table包裹起来就行了
1.eg:
3.虚拟滚动
1.window.requestAnimationFrame
4.cdn内容分发网络
cdn的原理是尽可能的在各个地方分布机房缓存数据,这样即使我们的根服务器远在国外,在国内的用户也可以通过国内的机房迅速加载资源
因此,我们可以将静态资源尽量使用cdn加载,由于浏览器对于单个域名并发请求上线,可以考虑使用多个cdn域名。并且对于cdn加载静态资源需要注意cdn域名要与主站不同,否则每次请求都会带上主站的cookie,平白消耗流量
5.nginx
1.正向代理和反向代理
2.负载均衡
1.定义
nginx的负载均衡做的事情就是根据服务器的能力去平衡大量的请求到达各个服务器的数量。这种平衡不是绝对的平均,当然,具体的怎么样的去平衡请求,我们可以根据自己的需求去设置不同的平衡策略。
2.负载均衡模块
load-balance
load-balance是辅助模块主要为upstream模块服务
2.作用
从多台后端服务器中选择出一个合适的服务器处理当前请求
nginx负载均衡模块
ngx_http_upstram_module
允许定义一组服务器,这种服务器可以被proxy_pass,fastcgi_pass和memcached_pass这些指令引用
3.负载均衡策略
1.内置策略
1.轮询(默认)
每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器挂掉,能自动剔除
2.Weight(加权轮询)
指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况
3.ip_hash
每个请求按照访问ip的hash结果分配,这样每个方可固定访问一个后端服务器,就可以解决session问题(因为是固定访问,在身份验证上的压力较小)
2.扩展策略
1.fair(第三方)
按照后端服务器端的响应时间来分配请求,响应时间短的优先分配
2.url_hash(第三方)
分支主题
3.动静分离
1.概念
1.服务器上
让静态资源走静态资源服务器、动态资源走动态资源服务器
静态资源
为静态资源准备专门的服务器,调优参数,与动态资源服务器分开。让静态资源分布在全国不同的服务器上,就近缓存到最近的服务器上。
优点
不再请求原有的真实服务器,分担源服务器的压力,提高就近访问的速度
动态资源
反向拉取即可
2.程序
让程序上将不经常发生改变的内容静态化,经常变化的内容动态化
让一次的数据没有变化,查询没有变化的时候,属于将文件静态化
3.文件上
让运算资源文件(php,aspx,jsp)等与静态资源文件(jpg,png,css,js)走不同的文件
2.常用方式
1.cdn
内容分发网络
将压力较大的服务器的内容进行转发
2.nginx
3.优点
1.api接口服务化
2.前后端开发并行
3.减轻后端服务器压力,提高静态资源访问速度
4.缺点
1.跨域
1.原因
因为走了不同的服务器,静态资源和动态资源分放在不同服务器上面,也就是存放在不同的资源地址上
eg:静态资源: http://static.com
动态资源:http://constuct.com
从http://constuct.com访问http://static.com
存在了跨域
2.解决方法
使用nginx进行拦截
1.当访问http://constuct.com/static的时候 使用nginx拦截转发到static.constuct.com
2.当访问到static.constuctcom时候转发到真实的地址
2.分布式session
1.原因
因为session是存储在服务器端的,当服务器集群部署的话默认是被轮询访问的,这时候一台服务器存储的有session,另一个服务器没有存储session就会产生分布式session的问题
6.图片优化
1.计算图片大小
1.如何计算图片大小
对于一张100*100像素的图片来说,图像上有10000个像素点,如果每个像素的值是rgba存储的话,就是是每个像素有4个通道,每个通道1个
字节(8位=1个字节),那么该图标大小大概是39KB(10000*1*4/1024)
2.优化点
在实际项目中,一张图片可能不需要使用那么多的颜色去显示,我们可以通过减少每个像素的调色板来相应缩小图片的大小
3.思路
1.减少像素点
2.减少每个像素点能够显示的颜色
2.图片加载优化
1.不用图片,很多时候会使用到修饰类图片,这类图片完全可以用css代替
2.对于移动端来说,屏幕宽度就那么点,完全没有必要去加载原图浪费带宽。一般图片都用CDN加载,可以计算出适配屏幕的宽度,然后去请求相应裁剪好的图片。
3.小图使用base4格式
4.将多个图标文件整合到一张图片中(雪碧图)
5.选择正确的图片格式
1.对于能够显示webpd格式的浏览器尽量使用webp格式。因为webp格式具有更好的数据压缩算法,能够代理更小的图片体积,而且拥有肉眼识别无差异的图像质量,缺点就是兼容性并不好
2.小图使用png,其实对于大部分图标这类图片,完全可以用svg代替
3.照片使用JPEG
7.DNS预解析
DNS解析也是需要时间的,可以通过预解析的发生来预先获得域名所对应的IP
分支主题
8.防抖节流
9.预加载
在开发中,可能会遇到这样的情况,有些资源不需要马上用到,但是希望尽早获取,这个时候可以使用预加载
预加载其实是声明式的fetch,强制浏览器请求资源,并且捕获阻塞onload事件,可以使用以下代码开启预加载
分支主题
预加载可以一定程度上降低首屏的加载时间,因为可以将一些不影响首屏但重要的文件延后加载,唯一缺点就是兼容性不好。
10.预渲染
可以通过预渲染将下载的文件预先在后台渲染,可以使用以下代码开启预渲染
分支主题
预渲染虽然可以提供页面的加载速度,但是要确保该页面大概率会被用户在之后打开,否则就是白白浪费资源去渲染
11.懒加载
懒加载就是将不关键的资源延后加载
懒加载的原理就是只加载自定义区域(通常是可视区域,但也可以是即将进入可视区域)内需要加载的东西。对于图片来说,先设置图片标签的src属为一张占位图,将真实的图片资源放入一个自定义属性中,当进入自定义区域是,就将自定义属性替换为src属性,这样图片就会去下载资源,实现了图片懒加载
懒加载不仅可以用于图片,也可以使用在别的资源上。比如进入可视区域才开始播放视频等等
12.性能监控
1.对于性能监控来说,我们可以直接使用浏览器自到的performance API来实现这个功能
2.对于性能监控来说,我们只需要调用performance.getEntriesByType('navigation')就可以了,这段代码可以获得页面中各种详细的性能相关信息
这段代码返回一个数组,内部包含很多信息,从数据开始在网络中传输到页面加载完成都提供了相应的数据。
分支主题
13.从v8看性能优化
编码
1.常见前端开发规范
1.HTML
1.文档规范
前端网站遵循的文档模式为XHTML1.0 Transitional模式,参考最新改版的网站(taobao.com)及HTML发展趋势,页面所遵循的文档模式应改为
2.语义化标签
随着HTML5语义化标签的出现,HTML原来以DIV布局的方式也慢慢的在改变;目前常用的语义化标签有article nav aside section header footer hgroup;
注意:因语义化在低版本的浏览器中不识别,所以要做处理,目前处理的方法是用JS的Document.createElement的方式,把需要用到的标签添加到window对象中。
3.css和js引入顺序
为网站性能考虑,页面的CSS都在head中引入,JS在底部引入
4.meta 中name和http-equiv
这两块是页面中的重要特性的设置,但所有页面设置格式基本相同
5.产品图片必须加上alt属性; 给重要的元素和截断的元素加上title;可以的话,尽量给所有图片都设定好高度和宽度;目的:有利于seo,搜索引擎的爬虫。
6.给区块代码及重要功能(比如循环)加上注释, 方便后台程序员嵌套模版
eg:
sdddfdsss
8.特殊符号使用:
尽可能使用代码替代: 比如 (>) & 空格( ) & ?(?) 等等;
2.CSS
1.ID、class命名
1.ID采用驼峰式命名法,如:mainMenuNav、subContentList等
Class采用下划线命名法,如:name_list、main_menu_content等
2.常见词汇
页 眉:header
内 容:content
容 器:container
页 脚:footer
版 权:copyright
导 航:menu
主导航:mainMenu
子导航:subMenu
标 志:logo
标 语:banner
标 题:title
侧边栏:sidebar
图 标:Icon
注 释:note
搜 索:search
按 钮:btn
登 录:login
链 接:link
信息框:manage
2.Css中背景图片
Css中的背景图片可以合并的都合并成一张图片,这样可以减少页面的HTTP请求;涉及到应用到背景图片的Css都放置Css文件中的顶部,这样便于后期维护。
3.Css文件中,单独的样式定义,不要折行,这样便于浏览和查看,也易于维护
4.页面中较为公用的模块(如:点评、POI、在线问答),其Css要独立成单独的Css文件,这样便于不同类页面之间直接引用和后期统一维护
5.Css3的使用规范
Css3新增的属性有border-radius,box-shadow,transition,transform,animation,@font-face, gradient等,这些新的属性虽然兼容性还有些问题,但是可以在不破坏低版本浏览器页面样式的情况下,丰富高版本浏览器的交互;所以建议适量的使用。
6.Font-family属性值用英文
3.Js
1.缩进
2.语句结尾
3.命名
1.变量和方法名统一使用驼峰命名法(小)
2.JS文件统一使用驼峰命名法(大)
3.变量中禁止使用动词开头,比如禁止使用get/set等,需要以名词开头。方法命名须要以动词开头,文件名称一律以名词开头;
eg:好的变量命名 var userName = “”;
不好的变量命名 var UserName = “”;
好的方法命名 function getUserName(){…};
不好的方法命名 function getusername(){…};
4.常量
常量一律使用大写表示单词和单词之间使用(_)下划线进行区分。
eg:好的常量定义 var MAX_COUNT = 10;
5.构造函数
构造函数的命名以大写字母开始(大写驼峰)
eg:好的构造函数 function HotelList(){…}
6.直接量(变量默认值)
字符串定义 var userName = “”;
数字定义 var count = 0;
布尔定义 var flag = false;
预定义对象 var obj = null;
对象直接量 var book = {};
数组直接量: var books = [];
7.注释
1.单行注释
重要的逻辑语句之前需要添加单行注释(看情况定)
2.多行注释
每个方法之前需要添加多行注释(看情况定)
3.文档注释
例子
//////////////////////////////////////////////
// 这个文件是 途牛 NGBOSS 系统项目的一部分
//
// Copyright (c) 2013 Tuniu
//////////////////////////////////////////////
/**
* 功能说明:…..
* @author: 作者姓名 (xxx@tuniu.com)
* @version: xxxx.js 2013-09-17 14:21:30
*/
4.图片
1.背景图
1.可以合并的背景图合并到统一张图片中,即CSS Sprite
2.合并后的图片在CSS引用时,放在CSS文件的最顶部
3.Font-face,可以使用的尽量使用
2.产品图
1.首屏之外的产品图片都异步加载
2.产品图片的尺寸确定的,定义样式时要把宽和高固定
5.性能
1.网站前端优化 – DOM
DOM优化方法
目前对DOM优化采用的方法是不渲染,即将对SEO不重要的内容用textarea或者script包裹,这样的话他们在渲染时就会被当做字符串而不会解析成节点。
2.网站前端优化 – JS
JS是除图片外,对前端性能影响最大的一个方面,也是最难优化的。总体来说,JS对性能有影响体现在两个阶段,一个是JS的下载阶段,一个是执行阶段。
JS同步时,下载和执行阶段解析器都会暂停,等待JS下载和执行;而jS异步时,JS下载不会暂停解析器,因此不会阻塞页面,但是执行时,仍然会暂停解析器。所以,对JS处理方式一般是异步并且放在页面底部。这样可以对页面的影响降到最小。
JS另一个难点就是页面中的JS代码的逻辑处理
3.网站前端优化 – 重绘&回流
1.回流:
当呈现树中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流(其实我觉得叫重新布局更简单明了些)。每个页面至少需要一次回流,就是在页面第一次加载的时候。
2.重绘
当呈现树中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color。则就叫称为重绘。
4.这块内容是和浏览器渲染方式息息相关的,这里只介绍些平时我们可能使用的一些会造成重绘&回流的方法,及改进意见
1.不要一个个改变元素的样式属性,最好直接改变class_name,但class_name是预先定义好的样式,不是动态的,如果你要动态改变一些样式,则使用cssText来改变
2.让要操作的元素进行"离线处理",处理完后一起更新,这里所谓的"离线处理"即让元素不存在呈现树中
3.不要经常访问会引起浏览器flush队列的属性,如果你确实要访问,就先读取到变量中进行缓存,以后用的时候直接读取变量就可以了
4.考虑你的操作会影响到呈现树中的多少节点以及影响的方式,影响越多,花费肯定就越多
6.SEO
1.可抓取性
1.所有SEO内容中的链接采用文字并且包含关键词,不得采用仅仅图片、flash、iframe以及AJAX等特殊方式加载,保证链接可被搜索引擎爬虫抓取。上线前采用Lynx浏览器或者采用在线版:http://lynx.itlearner.com/检查链接的可抓取情况。
2.所有的SEO内容应当直接显示在源代码中,不要使用sessionID, DHTML, cookies, Javascript(textarea), Flash等技术所展现内容。采用Lynx浏览器或者采用在线版:http://lynx.itlearner.com/检查内容的展示情况。
3.不要将文字隐藏在图片之后,或者文字颜色与背景色相同,会被判定为隐藏内容。唯一可行的方法是使用text-indent属性。
2.标准化
1.遵循xhtml规则,所有标签必须闭合,比如 不能忘记添加。所有页面改版或上线前,必须使用工具验证生成后的代码,确保没有未闭合的标签。
https://chrome.google.com/webstore/detail/html-tag-checker/ohdllebchmmponnofchalfkegpjojcaf?hl=zh-CN
2.使用语义化的标签进行页面的规划,例如:分段使用而不是,列表使用,表格使用等标签,避免多余嵌套,页面正文内容必须处于最深的嵌套中。
3.不要使用空的标签,例如,禁止出现空的
4.合理使用H1~H6标签,使网页文本具有层次性,H1标签只允许出现1次,被H1标签包裹的文字必须能概括本页面的内容,页面上与之相关的一些标签依次使用H2加强,不使用H3~H6标签。不要通过css去修改h标签的大小加粗的样式。
3.简洁化
1.不使用行内样式和内的css样式,防止造成页面重渲染,降低效率。
2.减少页面上的无关信息,无意义的代码、隐藏菜单和广告等,使用js进行调用,提高页面的信噪比
3.预先在中定义好每个图片的大小,便于用户加载的时候可以预留足够的空间,防止图片加载不出来破坏页面结构。页面上的所有图片必须加上alt属性,对于除小图标之外的照片,只使用jpg和png格式。不要使用html控制图片大小进行缩放,如果产品图片尺寸与我们的需要不一致,在上传的时候就自动裁剪压缩好;如果需要缩略图,使用两个版本大小的图片,并且通过存放不同目录或者设置件名特征,禁止搜索引擎爬行缩略图。
4.页面总体积小于110K,共享CSS样式和脚本样式,相同样式用户只需下载一次,压缩CSS文件中的空白。压缩JS代码,移除重复无用的JS代码,对JS文件体积减肥,实现代码简洁化。合并JS、CSS文件以减少HTTP请求。压缩HTML代码中无意义的TAB、空白元素。
5.小图标不需要alt属性,alt属性的内容必须与图片内容相符合,如无法调用到相关的替代文字,则不写alt属性,不允许出现空的alt属性。
6.当锚文本内容无法与页面主题相关时,请增加title属性帮助搜索引擎了解目标页面的内容,除此之外不需要任何title属性
7.页面发布前必须压缩删除代码中的空白,注释等无意义内容
4需商议的部分
1.制定前端代码元素命名标准,做到元素命名的语义化和统一。
2.在输出的html代码中不要出现css和js代码,此类代码一律外置
3.页面html代码行数不超过1000行。把代码压缩换行
提高js代码优雅性的几个技巧
1.遇见多个条件怎么处理
1.some方法
const conditions = [“Condition 2”,“Condition String2”];
someFunction(str){
if(str.includes(“someValue1”) || str.includes(“someValue2”)){
return true
} else {
return false
}
}
可变为
someFunction(str){
const conditions = [“someValue1”,“someValue2”];
return conditions.some(condition=>str.includes(condition));
}
2.对象属性
function whatFood(mealtime) {
let food = '';
if (mealtime === 'breakfasttime') {
food = 'egg';
} else if (mealtime === 'lunchtime') {
food = 'vegetable'
} else if (mealtime === 'dinnertime') {
food = 'fruit'
} else {
food = 'cookie'
}
return food;
}
可变为
function whatFood(mealtime) {
const food = {
breakfasttime: 'egg',
lunchtime: 'vegetable',
dinnertime: 'fruit'
}
return food[mealtime] ? food[mealtime] : 'cookie';
}
2.避免过多的函数参数
通过结构赋值
function myFunction(employeeName,jobTitle,yrExp,majorExp){
return ${employeeName} is working as ${jobTitle} with ${yrExp} years of experience in ${majorExp}
}
console.log(myFunction(“John”,“Project Manager”,12,“Project Management”))
function myFunction({employeeName,jobTitle,yrExp,majorExp}){
return ${employeeName} is working as ${jobTitle} with ${yrExp} years of experience in ${majorExp}
}
const mockTechPeople = {
employeeName:“John”,
jobTitle:“Project Manager”,
yrExp:12,
majorExp:“Project Management”
}
console.log(myFunction(mockTechPeople))
3.js中的return必须写在每一行结尾而不是下一行,这样会避免 return 设计错误。
js中除了function 后面一律都应该自己手动添加 ; return 后面千万不要跟 换行(回车)
原因
js的自动补全机制
组件化封装设计思路
1.意义:
组件化开发的意义有很多,一些新手会狭隘的认为只是单纯为了复用(包括对模块化的理解),
认为只有一个地方用就没必要抽取封装为组件,实际上不尽然
1.组件化是对实现的分层,是更有效地代码组合方式
2.组件化是对资源的重组和优化,从而使得项目资源更合理
3.组件化有利于单元测试
4.组件化对重构友好
2.组件与模块
模块通常强调的是职责(分离、内聚),组件是可复用模块和相关依赖的封装。
组件可以这样定义
1.可复用的模块,完成既定功能
2.有明确的接口规定
3.有上下文依赖,外部依赖资源的定义
4.可以独立发布
element-ui使用中的坑
1.el-table发生抖动
原因
通过阅读代码结构,发现el-table-column通过template循环生成,由于template的作用是模板占位符,可帮助我们包裹元素,但在循环过程当中,template不会被渲染到页面上。有关表格数据渲染中key的作用如下:
key作为一个DOM节点的标识值,结合Diff算法可以实现对节点的复用。(key相同的节点会被复用);
只有当key(或其他导致isSameNode判断为false)发生改变时,才会触发节点的重新渲染。否则Vue将会复用之前的节点,通过改变节点的属性来实现节点的更新。
同时,template标签不支持:key属性,
diff过程中优先判断key,每一次渲染视图会缓存一次dom树,第二次渲染新树时和第一次渲染的旧树进行比较,
优先判断key,如果key一样就表示dom没有发生变化,直接复用,被复用的地方不刷新,如果不一样就会触发sameVnodes,引起页面重绘
1.使用key绑定math.random
原因:每一次都会计算一次math.radom,导致每一次更改table,key都会发生改变,触发diff的sameVnode进行刷新,重新计算了el-table的表头长度
解决:给key绑定固定值
2.上述方法不行,强制设置el-table{width:99.99%!important}
强制设置表格长度,el-table重新计算的表头长度无法使用,只能使用固定值
2.el-table
1.selection-change
可以获取选择的数据
2.想要在翻页然后返回来的时候回显选中的数据
1.需要绑定row-key
:row-key="getrowKey"
2.需要绑定reserve-selection为true·
3.绑定这两个还有一个好处
el-table中的数据和接口返回数据存在不同(el-table会多出checked属性,但是绑定id可以解决这个问题
1.回显时:无需判断tableData中是否item.id等于select的item.id来回显选中状态
3.需要将接口返回的数据回显到el-table中
this.refs['xx'].toggleRowSelection
接收两个参数(obj,true)
3.el-dropdown
el-dropdown-item 的热区太小,根据文字设置内部热区的宽度,当文字偏小,外部item的宽度偏大,就容易造成点击无法生效的假象
4.el-select
1.el-select的多选options的子选项自带一个keyup事件
2.在el-select的主输入框中绑定keyup事件和blur事件会只在输入框中有焦点生效
0 条评论
下一页