前端要会打组合拳,复盘30+技术点打出的功能
大厂技术 高级前端 Node进阶
点击上方 程序员成长指北,关注公众号
回复1,加入高级Node交流群
前端要会打组合拳,复盘30+技术点打出的功能
一、前言
接续前文:
原创|进阶图(一):主面板开发[1]
原创|进阶图(二):关联资料和缩放支持设计[2]
tips:总结。
①会用才算学到,能灵活运用打组合拳是学会的标志之一。
②每一个技术点都值得优写优学,当他们组合在一起可能会有惊喜。
③要用的时候能想到,想到的时候会用,用的时候能优雅,就是精通了。这也是我坚持写“每个技术点都值得优学优写系列”的初衷。
④写到后面有点疲惫,其实可以算是50+的知识技术点,组合一起偷懒了。
⑤前端是真的知识点广啊啊啊,更新迭代还快,不总结没发现,一总结吓一跳,我不想说前端卷,看看下面这张图。
原创的手写进阶图,前文已经开发完,今天总结一下,涉及到的前端知识技术点,看看开发一个这样的进阶图,需要用到哪些知识和技术点。
会用的知识技术才算学到的,进阶图的每一步都是作者原创,市面上并没有发现参考库,虽说难度不大,但这其中也涉及到不少的前端知识技术点,最重要的是涉及到的思维组织,逻辑设计,技术点的灵活配套运用,知道该用什么技术点实现什么,在什么时候用。
我一共总结了涉及到的30+知识技术点,也有更可能不止,欢迎评论区分享。
二、30+前端技术点
这些知识技术点被分为下面几个系列:
1. Vue 系列
1. props
进阶图用到 props 主要是用来接收父组件传递而来的主面板数据,例如 hasScale 用于在父组件调用面板组件时,传递一个 Boolean 值告诉面板组件是否支持缩放。而 progressData 则是用来接收渲染面板的数据,要注意的是,父组件中的传递名称应该和子组件中的 props 中定义的名称一致。如下是关于 props 在进阶图中的应用。
props 可以是数组或对象,用于接收来自父组件的数据。props 可以是简单的数组,或者使用对象作为替代,对象允许配置高级选项,如类型检测、自定义验证和设置默认值。支持配置属性 type:数据类型,default 设置默认值,required 是否必须,validator 自定义验证函数。
"list"></main-panel>
复制代码
props: {
// 是否支持缩放
hasScale: {
type: Boolean,
default: false
},
// 类型:只读(detail)或 编辑(默认)
type: {
type: String,
default: ''
},
// 主面板数据
progressData: {
type: Array,
default: function () {
return []
}
}
},
复制代码
2. $emit
$emit 用于向上派发事件并传递参数,通常配合 props 使用,以达到父子组件通信的目的。进阶图中是于父组件派发change事件,并传递 this.bodyWidth, this.list 两个参数。注意父组件在接收事件时应保持名称一致。
watch: {
'list': {
deep: true,
handler (newVal, oldVal) {
this.bodyWidth = this.list.length * 392 + 60 + 'px'
// 派发事件
this.$emit('change', this.bodyWidth, this.list)
}
},
},
复制代码
<-- 接收 change 事件 -->
<main-panel @change="change">main-panel>
复制代码
3. ref
ref 在 Vue 中用于绑定组件,可以通过 this.refs[绑定名称]或this.refs[绑定名称] 或 this.refs[绑定名称]或this.refs.绑定名称 来获取组件实例对象,这有时非常有用。例如,当我们想要在一个组件中调用其子组件的某个方法或属性时,可通过这种方式调用。
<-- 使用 ref 绑定面板组件 -->
<main-panel ref="mainPanel">main-panel>
复制代码
4. watch
watch 是 vue 中被常用的 api 之一,用于监听数据,可以监听 data 中的数据,也可以监听 props 中的数据。
watch 观察 Vue 实例上的一个表达式或者一个函数计算结果的变化。回调函数得到的参数为新值和旧值。表达式只接受简单的键路径。对于更复杂的表达式,用一个函数取代。
进阶图中使用 watch 监听 data 中的面板数据 list 和 props 中的 父组件传递下来的面板数据 progressData。其中使用到了 deep 属性,表示是否进行深层次的内部值得监听。根据官网的提示,数组其实不需要使用 deep:true 去监听数组内部值得变化。
watch: {
'list': {
deep: true,
handler (newVal, oldVal) {
this.bodyWidth = this.list.length * 392 + 60 + 'px'
this.$emit('change', this.bodyWidth, this.list)
}
},
'progressData': {
handler (newVal, oldVal) {
this.list = newVal
}
}
},
复制代码
5. computed
computed 是计算属性,对于任何复杂逻辑,你都应当使用计算属性,这就是它的应用场景,虽然通过 methods 或 watch 也能完成,但是 computed 在处理复杂逻辑时更有优势:计算属性是基于它们的响应式依赖进行缓存的。
进阶图的实现多次用到了 computed
6. created
created 声明周期钩子函数之一,如果你想尽早获取接口数据,那么在这里做很合适。
在实例创建完成后被立即同步调用。在这一步中,实例已完成对选项的处理, 意味着以下内容已被配置完毕:数据侦听、计算属性、方法、事件/侦听器的回调函数。然而,挂载阶段还没开始,且 $el property 目前尚不可用。
进阶图中就是在 created 中获取可提供的关联数据。
created () {
// 获取可供关联的关联数据
// this.searchList()
},
复制代码
7. mounted
mounted 是一个 vue 生命周期钩子函数,此时 dom 这时 el 被新创建的 vm.$el 替换了,我们可以在 mounted 中进行 dom 操作, 这也是最早可以较好进行 dom 操作的钩子函数。
注意 mounted 不会保证所有的子组件也都被挂载完成。如果你希望等到整个视图都渲染完毕再执行某些操作,
可以在 mounted 内部使用 vm.$nextTick
进阶图中使用 mounted 钩子,在里面做了两件事,第一件是监听文档上的 click 事件。第二件事是调用 init() 函数,初始化进阶图
mounted () {
// 监听 click 事件
document.addEventListener('click', this.clickListener)
// 初始化进阶图
this.init()
},
复制代码
8. beforeDestroy
我们通常在 beforeDestroy 中做一些解绑和移除操作。beforeDestroy 发生在实例销毁之前调用。在这一步,实例仍然完全可用。要注意的是,该钩子在服务器端渲染期间不被调用。
进阶图中在 beforeDestroy 中做的是 移除 click 监听,例如一些定时器也可以在这是移除,还一些解绑操作。
beforeDestroy () {
// 在实例被销毁前移除 click 监听
document.removeEventListener('click', this.clickListener)
},
复制代码
9. 指令 v-if
v-if 指令的应用场景可以是判断是否展示(是否渲染)某一个元素,一种条件判断指令。非常常用的指令之一,常被随之提起来是 v-show。他们都都可以做同样的事情, 所以常被比较,什么时候应该用哪个?
v-show 是通过改变 css display 属性值实现切换效果, v-if是真正的条件渲染, 当一开始的值为true时才会编译渲染,而v-show不管怎样都会编译,只是简单地css属性切换 v-if适合条件不经常改变的场景,因为他的切换会重新编译渲染,消耗较大。v-show适合切换较为频繁的场景,开销较小。
进阶图中使用 v-if 指令来判断是否支持缩放,即是否展示缩放工具栏,如下
10. v-for
用于遍历循环生成系列元素,这也是常用指令,key 属性应该被注意,如果你希望你的元素(组件)保持足够的独立性。
tips1:v-for 的默认行为会尝试原地修改元素而不是移动它们。要强制其重新排序元素,
你需要用特殊 attribute key 来提供一个排序提示。
tips2:v-if 和 v-for 当它们处于同一节点,v-for 的优先级比 v-if 更高, 这意味着 v-if 将分别重复运行于每个 v-for 循环中。
当你只想为部分项渲染节点时,这种优先级的机制会十分有用。如果不是这可能会造成不必要的消耗。
进阶图中使用 v-for 遍历生成系列阶梯节点和文本行节点,这系列节点构成了进阶图的主面板,如下
11. v-bind
v-bind最被常用,但通常我们使用它的简写“:”,它的用法是动态地绑定一个或多个 attribute, 或一个组件 prop 到表达式。
tips:修饰符:
.prop - 作为一个 DOM property 绑定而不是作为 attribute 绑定。(差别在哪里?)
.camel - (2.1.0+) 将 kebab-case attribute 名转换为 camelCase。(从 2.1.0 开始支持)
.sync (2.3.0+) 语法糖,会扩展成一个更新父组件绑定值的 v-on 侦听器。
进阶图中,例如 key,disabled 和 style 的动态绑定,如下
12. v-on
v-on 用于绑定事件,我们更常用的是它的缩写 “@”,结合一些修饰符使用,有时会非常有用,例如 click.stop 可以阻止冒泡。
tips 一些修饰符:
.stop - 调用 event.stopPropagation()。
.prevent - 调用 event.preventDefault()。
.capture - 添加事件侦听器时使用 capture 模式。
.self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。
.{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。
.native - 监听组件根元素的原生事件。
.once - 只触发一次回调。
.left - (2.2.0) 只当点击鼠标左键时触发。
.right - (2.2.0) 只当点击鼠标右键时触发。
.middle - (2.2.0) 只当点击鼠标中键时触发。
.passive - (2.3.0) 以 { passive: true } 模式添加侦听器
tips 从 2.4.0 开始,v-on 同样支持不带参数绑定一个事件/监听器键值对的对象。注意当使用对象语法时,是不支持任何修饰器的。
进阶图中主要是用于绑定事件,并配合 .stop 使用阻止事件冒泡,如下所示
13. v-html
v-html 用于绑定 html 字符串,它的作用是更新元素的 innerHTML。
tips1:在网站上动态渲染任意 HTML 是非常危险的,因为容易导致 XSS 攻击。只在可信内容上使用 v-html,永不用在用户提交的内容上。
tips2:在单文件组件里,scoped 的样式不会应用在 v-html 内部,因为那部分 HTML 没有被 Vue 的模板编译器处理。如果你希望针对 v-html 的内容设置带作用域的 CSS,你可以替换为 CSS Modules 或用一个额外的全局 元素手动设置类似 BEM 的作用域策略。
进阶图开发中,用 v-html 绑定可关联数据的 title,如下
<span v-html="item.title">span>
复制代码
14. v-model
v-model 可用于绑定表单组件的值,实现双向绑定。能使用 v-model 的元素包括四类:
components
tips:修饰符:
.lazy - 取代 input 监听 change 事件
.number - 输入字符串转为有效的数字
.trim - 输入首尾空格过滤
结合修饰符使用,有时会显得很有用,例如进阶图中使用 v-model.trim, 这样在输入链接文字的时候,就会自动去掉首尾的空格,而这并不影响功能, 而有时会很妙,例如一些 iOS 手机上在表单网页上常常在输入完成后会自动带上空格, 我遇到的一个例子是输入账号密码时,一不小心就携带了空格,而这并不友好, 如果使用 .trim 就好多了,这是指在这种场景下。
写到这里,我其实也没想到,一个进阶图涉及这么多技术点,所以平时应该积少成多, 养成学习写作积累的习惯。更多的积累,有时能够灵活配套打出一套更有力的拳。涉及 vue 的,可能还有更多技术点,欢迎关注的同学评论区指出。
2. JavaScript 和 Html 系列
15. addEventListener 和 removeEventListener
EventTarget.addEventListener() 方法将指定的监听器注册到 EventTarget 上,当该对象触发指定的事件时,指定的回调函数就会被执行。事件目标可以是一个文档上的元素 Element,Document和Window或者任何其他支持事件的对象 (比如 XMLHttpRequest)。
addEventListener()的工作原理是将实现EventListener的函数或对象添加到调用它的EventTarget上的指定事件类型的事件侦听器列表中。
进阶图开发中,使用 addEventListener 监听 click 事件, 监听回调为 clickListener,结合了 Element.contains() 以实现击行为发生在 menuPanel(菜单区域) 区域外,关闭右键弹起的菜单。如下:
mounted () {
// 监听 click 事件
document.addEventListener('click', this.clickListener)
},
beforeDestroy () {
// 移除监听
document.removeEventListener('click', this.clickListener)
},
复制代码
clickListener (event) {
if (this.type === 'detail') return
if (!this.$refs.menuPanel) return
// 点击行为发生在 menuPanel(菜单区域) 区域外,关闭右键弹起的菜单
// element.contains(),有时是非常有用的 api
if (this.$refs.menuPanel && !this.$refs.menuPanel.contains(event.target)) {
this.showMenu = false
}
},
复制代码
16. keyup.enter.native
keyup 事件在按键被松开时触发,keyup.enter 的作用是在 enter 回车键被松开的时候触发。这常常被用在登录、检索、和表单提交等需要回车键表示发送或确定的场景中。
进阶图中就是为实现回车键 Enter 被松开时触发检索关联数据而使用。如下
<el-input v-model="searchValue" @keyup.enter.native="clickSearch" placeholder="检索姓名或工号">el-input>
复制代码
17. new Date()
new Date() 是 javascript 的全局 api,可以用来创建当前时间。进阶图开发中, 是在生成 uuid 时用来获取当前时间的毫秒数。如下:
// 获取当前时间的毫秒数
let d = new Date().getTime()
// console.log(d) 1651127122490
复制代码
18. window.performance.now()
据 mozilla:该方法返回一个DOMHighResTimeStamp对象,该对象表示从某一时刻(译者注:某一时刻通常是 navigationStart 事件发生时刻)到调用该方法时刻的毫秒数。
19. Math.random() 和 Math.floor
Math 是 javascript 的一个全局 api, Math.random() 的返回值是一个浮点型伪随机数字,范围是[0,1)。Math.floor() 的作用是为向下取整,返回一个整数。
来自 mozilla 的tips:Math.random() 不能提供像密码一样安全的随机数字。不要使用它们来处理有关安全的事情。使用Web Crypto API 来代替, 和更精确的window.crypto.getRandomValues() 方法.
20. String.replace()
String.replace() 被用于替换字符,但不会改变原字符串,而是返回改变后的字符串。
tips:replace() 方法返回一个由替换值(replacement)替换部分或所有的模式(pattern)匹配项后的新字符串。
模式可以是一个字符串或者一个正则表达式,替换值可以是一个字符串或者一个每次匹配都要调用的回调函数。如果pattern是字符串,则仅替换第一个匹配项。
21. toString()
方法返回一个表示该对象的字符串,可以用于将数字(number)转换为字符串(string)。
22. Array.push()、Array.map()、Array.findIndex() 和 Array.splice()
push() 可用于向数组添加数据项,在数组尾部添加;map() 可用于遍历数组;findIndex() 可用于查找符合条件的数据项;splice() 可用于删除数组中的元素,或在某个位置添加元素。
进阶图开发中都用到了这些数组的方法,例如 findIndex 和 push 结合使用,避免重复添加数据,举例如下:
23. JSON.parse() 和 JSON.stringify()
JSON.parse() 这套组合还被我常用于 storage 的存储中,主要是为了保持数据的完整性和真实性, 例如一个 int 数字不会被改动为 string。进阶图开发中,使用 JSON.parse() 和 JSON.stringify() 实现深拷贝, 深拷贝之后拷贝前后的两份数据将是完整独立的, 一方的变动不会影响另一方。如下:
this.form.relation.push(JSON.parse(JSON.stringify(this.outItem)))
复制代码
24. window.open()
tips:Window 接口的 open() 方法,是用指定的名称将指定的资源加载到浏览器上下文(窗口 window ,内嵌框架 iframe 或者标签 tab )。如果没有指定名称,则一个新的窗口会被打开并且指定的资源会被加载进这个窗口的浏览器上下文中。
window.open() 在进阶图开发中,用于打开一个新窗口访问详情页。如下
25. MouseEvent.screenX 和 MouseEvent.screenY
screenX 是 MouseEvent 的只读属性,提供鼠标在全局(屏幕)中的水平坐标(偏移量)。screenY 则是提供鼠标在全局(屏幕)中的垂直坐标(偏移量)。
在进阶图开发中,是利用鼠标的这两个坐标结合固定定位实现右键菜单的位置是跟随鼠标位置的。如下:
26. localStorage
可以使用键值对的形式,存取数据到 localStorage,存到 localStorage 中的数据可以被永久存储, 除非被主动删除。
进阶图开发中,适用于缓存进阶图数据,如下:
localStorage.setItem('progressData', progressData)
复制代码
**27. new FormData() 和 canvas.toBlob() **
canvas.toBlob() 可以将 canvas 元素中的画布内容转换为 blob 形式。
FormData 接口提供了一种表示表单数据的键值对 key/value 的构造方式, 并且可以轻松的将数据通过XMLHttpRequest.send() 方法发送出去。如果送出时的编码类型被设为 "multipart/form-data",它会使用和表单一样的格式。
进阶图开发中,使用 new FormData() 来组织数据,上传 blob 格式的图片。如下:
28. event.currentTarget 和 switch
event.currentTarget 指向事件绑定的元素,请注意区分 Event.target 是指向事件触发的元素。进阶图开发中,是巧妙利用 currentTarget 获取事件绑定元素,进而获取该元素的 name 属性值。以实现区分不同元素进行的单击操作,进而进行不同的逻辑处理。
switch 语句评估一个表达式,将表达式的值与case子句匹配,并执行与该情况相关联的语句。因为是条件分支语句,所以当出现类似条件的多余等于三个分支时,可以考虑使用 switch 进行条件判断和处理。尽管 if 也可以实现目的,但 switch 此时可能看起来会更清晰。
进阶图中的使用如下:
3. css 和 scss
29. @mixin 和 @include
进阶图的开发使用了 scss 作为 css 预处理语言,其中使用了 @mixin 和 @include。
@mixin 指令允许我们定义一个可以在整个样式表中重复使用的样式。
@include 指令可以将混入(mixin)引入到文档中。
进阶图中的使用情况如下:
@mixin cn-icon($name,$w:20,$h:20) {
display: inline-block;
width: #{$w}px;
height: #{$h}px;
background: url('#{$name}') no-repeat center;
background-size: 100% 100%;
}
复制代码
.icon-head-home {
@include cn-icon("~@/assets/icon-head-home.png", 19, 19);
margin-right: 10px;
cursor: pointer;
}
复制代码
30. css浏览器兼容性写法前缀
tips:CSS非标准属性。厂商在实现非标准的CSS属性时,通常会加上前缀,甚至在将来会实现的标准也加,
当标准被发布后,厂商会将前缀移除。Firefox:-moz-,Chrome和Safari:-webkit-, IE:-ms-,Opera:-o-。书写建议私有属性(非标准)放在前面,标准属性写在后面,例如:
-webkit-transform:rotate(-3deg); /* Chrome/Safari */
-moz-transform:rotate(-3deg); /* Firefox */
-ms-transform:rotate(-3deg); /* IE */
-o-transform:rotate(-3deg); /* Opera */
transform:rotate(-3deg); /* 标准属性写在后面 */
复制代码
进阶图中是在 transform 中使用了兼容性写法,是为了更好的保证缩放功能的兼容性。如下:
.zoom-scale {
transform: scale(1.8);
-ms-transform: scale(1.8); /* IE 9 */
-webkit-transform: scale(1.8); /* Safari and Chrome */
}
复制代码
关于本文
作者:灵扁扁
https://juejin.cn/post/7095889556607598629
Node 社群
我组建了一个氛围特别好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你对Node.js学习感兴趣的话(后续有计划也可以),我们可以一起进行Node.js相关的交流、学习、共建。下方加 考拉 好友回复「Node」即可。
如果你觉得这篇内容对你有帮助,我想请你帮我2个小忙:
1. 点个「在看」,让更多人也能看到这篇文章 2. 订阅官方博客 www.inode.club 让我们一起成长 点赞和在看就是最大的支持