前端应该关注
功能,美观,无障碍,安全,性能,兼容性,用户体验
HTML
HyperText Markup Language
HyperText:包含图片、标题、链接、表格等
Markup 语法
Markdown 语法
HTML生成DOM树
<script setup> :
setup是 Vue 3 的一个语法糖,用于简化组合式 API 的使用。- 在
setup脚本中定义的变量和函数会自动暴露给模板,无需显式返回。
DOM Tree 会形成 Render Tree
某些情况下Render会合成自己的图层
插槽
可以在父组件中定义子组件内部的内容
默认插槽
父
<Child>
<p>This is the content of the default slot.</p>
</Child>
子
<slot></slot>
具名插槽(√)
父
<ChildComponent>
<template #header>
<h1>This is the header slot.</h1>
</template>
<p>This is the content of the default slot.</p>
<template #footer>
<p>This is the footer slot.</p>
</template>
</ChildComponent>
子
<slot name="header"></slot>
<slot name="footer"></slot>
<template>
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component"></component>
</keep-alive>
</router-view>
</template>
使用 v-slot 属性来获取当前匹配的组件实例,这里命名为 Component
<component :is="Component"> :
component是 Vue 提供的一个动态组件,is属性用于指定要渲染的具体组件。- 在这个例子中,
Component是从router-view的插槽中获取的当前匹配的组件。
作用域插槽
路由
routes是一个数组,每个元素是一个对象,表示一个路由。
routes:[
{
path:'/home',
redirect:'/home'//重定向,访问根路径 / 时,自动重定向到 /home
},
{
path:'/home',
cmponent:()=>import('@/......')//懒加载,只有在用户导航到相应路径时才会加载对应的组件。
}
]
导航守卫
router.beforeEach((to) => {
const userStore = useLoginStore()
userStore.token = localStorage.getItem('token') as unknown as string
if (!userStore.token && to.path !== '/login') return '/login'
})
router.beforeEach是 Vue Router 提供的导航守卫,用于在导航发生之前进行一些检查。to参数表示即将进入的目标路由。
-
导航守卫:
router.beforeEach是 Vue Router 提供的导航守卫,用于在导航发生之前进行一些检查。to参数表示即将进入的目标路由。
-
获取用户状态:
const userStore = useLoginStore()获取 Pinia store 实例。userStore.token = localStorage.getItem('token') as unknown as string从本地存储中获取用户的 token,并将其赋值给userStore。
-
检查登录状态:
if (!userStore.token && to.path !== '/login') return '/login'检查用户是否已登录(即userStore.token是否存在)。- 如果用户未登录且目标路径不是
/login,则重定向到/login。
<keep-alive> 组件来缓存路由组件
<template>
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component"></component>
</keep-alive>
</router-view>
</template>
媒体查询
@media all and (max-width: 640px){
...
}
mediatype
all: 适用于所有设备。
screen: 屏幕(电脑、平板、手机等)
print: 打印机和打印预览
speech: 语音设备(屏幕阅读器等)
*注:可用not/only修饰,表示不匹配/只匹配
CSS
Cascading 层叠
Style Sheets 样式表
层叠--------------------------》解决冲突
样式表-》规则声明的集合-》产生冲突-》解决冲突
例如
#title和h1都作用于同一个标签上
规则集合内就会产生冲突,层叠会解决这个冲突
层叠三大规则
生效优先级
样式表来源>选择器优先级>源码位置
样式表来源
用户代理样式(浏览器默认)>用户样式表(少有)>作者样式表(developer写的)
选择器优先级
选择器
内联 > id > class = attribute = pseudo-class > type = pseudo-element
选择器尽量少用id,!imortant(级别最高),自己的样式加载到引用库后面
简要发展史
目前是CSS3
CSS3前 常规流(有块级格式化上下文和内联格式化上下文)+float浮动流+Positioning定位流
CSS3后 Flex弹性布局 + Grid网格布局 + Multicol多列布局 + 一维二维空间布局 + 文本内容的多列展示
浏览器前缀
用于标识 CSS 属性 或 规则尚未成为W3C标准的一部分
这些前缀有助于确保新属性在老版本浏览器中的兼容性
div {
/* WebKit 内核 的 浏览器 的 私有前缀 , 如 : Chrome 和 Safari 浏览器 */
-webkit-border-radius: 10px;
/* Gecko 内核 的 浏览器 的 私有前缀 , 如 : Firefox 浏览器 */
-moz-border-radius: 10px;
/* Trident 内核 的 浏览器 的 私有前缀 , 如 : Internet Explorer 浏览器 */
-ms-border-radius: 10px;
/* Presto 内核 的 浏览器 的 私有前缀 , 如 : Opera 浏览器 */
-o-border-radius: 10px;
/* 正常的 不带 浏览器私有前缀 的 CSS 属性 */
border-radius: 10px;
}
盒子
格式化上下文
外部显示类型(display-outside)
规定盒子如何与统一格式上下文中的其他元素一起显示
内部显示类型( display-inside )
规定盒子内部布局方式,比如
display: flex (外部显示为block ) 参与BFC(块级格式化上下文)
display:inline-flex (外部显示为inline) 参与IFC(内联级格式化上下文)
BFC
块级格式化上下文
FC(Formatting Context)(格式化上下文)
所有的盒子都属于FC
可能属于一个BFC(block)(div/p/h1)、也可能是IFC(inline)(a/span/i/img)
会生成BFC的情况
BFC的作用
帮助盒子一个挨着一个沿着垂直方向排布
margin就是由BFC来解析的
两个盒子都设置margin时候会折叠,就是BFC在起作用
在同一个BFC里,两个盒子的margin才会折叠
HTML可以形成标准流,因为本身就是一个独立的BFC环境
在BFC中,每个元素的左边缘是紧挨着包含块的左边缘的
BFC可以解决
margin的折叠问题
浮动的高度塌陷问题
形成新的BFC
//只要overflow: !!不是!! visible
可以是 auto/hidden/scroll
解决折叠问题
//父级包裹两个元素
div content
div item
div item
div
//css创建BFC
.content{
overflow: auto;
}
解决浮动高度塌陷
条件
//父元素触发BFC,形成独立块级格式化上下文
//父元素高度为auto
BFC的计算方式
1.如果只有inline-level,是行高的顶部和底部的距离
2.如果有block-level,是由最底层的块上边缘和最底层块盒子的下边缘之间的距离
3.如果有绝对定位元素,将被忽略;
4.如果有浮动元素,那么会增加高度以包括这些浮动元素的下边缘
overflow
overflow: visible; //可见
overflow: hidden; //隐藏(可滚动的容器)
overflow: clip; //剪辑(禁止滚动)
overflow: scroll; //滚动(浏览器总是显示滚动条)
overflow: auto; //自动(如果内容溢出,则浏览器提供滚动条)
overflow: hidden; //覆盖(滚动条绘制在内容之上,而不是占据空间)
IFC
内联级格式化上下文
盒子会从包含块的顶部开始,按水平排列
这些盒子可以以不同的方式对齐
包含一串盒子的矩形区域就是一个 “线条框(line box)”
对齐方式
层叠上下文
对HTML元素的三维构想,基于用户界面z轴的上下排布
对于浏览器渲染过程的“渲染层(render layer)”
层叠水平
也就是层叠顺序
z-index只能在同一个层叠上下文比较
子元素的z-index无法超过父元素的z-index顺序
定位
grid网格布局
新的长度单位:fr
一般来说 1fr 的意思是“100%的剩余空间”, .25fr 意味着“25%的剩余空间”。当时当 fr 大于 1 的时候,则会重新计算比例来分配。
grid布局
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
等价于(repeat)
grid-template-columns: repeat(4, 1fr);
grid-template-columns: repeat(4, .25fr);
一般都建议使用 fr>=1 的情况
响应式设计
这里 A 和 D 都是固定的 50px,C 是占总宽度的 20%,剩余空间就可以分配给 B。
.grid-container {
grid-template-columns: 50px 1fr 20% 50px;
column-gap: 10px;
}
船新用法
3*3的网格
//网格布局
.face {
display: grid;
grid-template-rows:repeat(3,1fr);
grid-template-columns: repeat(3,lfr);
grid-template-areas:
"lt . rt"
"lc cc rc"
"lb . rb";
}
//规划块布局
.lt-dot{
grid-area: lt;
}
.lr-dot{
grid-area: lr;
}
.lc-dot{
grid-area: lc;
}
......
相比Flex
Flex是一维布局,Grid是二维
浏览器对Flex的兼容性更好
Grid适用于大面积的整体布局
小面积组件Flex更灵活
3D
重磅CSS属性
transform
transform-style: preserve-3d;/*所有子元素在3D空间中呈现*/
偏移
transform: translateX(90px) translateY(90px) translateZ(90px);/*左右 下上 前后*/
旋转
transform: rotateX(0deg) rotateY(0deg) rotateZ(0deg)
grid+transform实现页面3D骰子
实战效果
HTML
<div class="container">
<div class="wrap" id="dice">
<div class="face face-grid first-face">
<span class="dot cc-dot red"></span>
</div>
<div class="face face-grid second-face">
<span class="dot lt-dot"></span>
<span class="dot rb-dot"></span>
</div>
<div class="face face-grid third-face">
<span class="dot lt-dot"></span>
<span class="dot cc-dot"></span>
<span class="dot rb-dot"></span>
</div>
<div class="face face-grid forth-face">
<span class="dot lt-dot"></span>
<span class="dot lb-dot"></span>
<span class="dot rt-dot"></span>
<span class="dot rb-dot"></span>
</div>
<div class="face face-grid fifth-face">
<span class="dot lt-dot"></span>
<span class="dot lb-dot"></span>
<span class="dot cc-dot"></span>
<span class="dot rt-dot"></span>
<span class="dot rb-dot"></span>
</div>
<div class="face face-grid sixth-face">
<span class="dot lt-dot red"></span>
<span class="dot lc-dot red"></span>
<span class="dot lb-dot red"></span>
<span class="dot rt-dot red"></span>
<span class="dot rc-dot red"></span>
<span class="dot rb-dot red"></span>
</div>
</div>
</div>
结构
container //外层占位容器
wrap / dice //控制旋转
face / face-grid * 6 //面
dot / red //点
CSS
box-sizing
div {
box-sizing: border-box;/*元素的width和height包括content、padding和border的宽度,但不包括margin*/
}
渐变边框技术做面
.face {
position: absolute;
width: 120px;
height: 120px;
padding: 20px;/*w/h/p都包裹边框的宽度,是从边框的最里往里padding*/
opacity: 0.95;
border: 8px solid transparent; /*8px的透明边框,就是渐变边框的宽度*/
background-clip: padding-box, border-box;/*必要的两项*/
background-origin: padding-box, border-box;/*必要的两项*/
background-image:
linear-gradient(135deg, #e1eeffbb, #f3d5ffbb),
linear-gradient(135deg, rgb(0, 60, 255), rgb(0, 225, 255), #f0f);/*渐变角度+渐变颜色*/
}
grid做点(face-grid)
.face-grid {
/*骰子点数布局*/
display: grid;
grid-template-rows: repeat(3, 1fr);/*行*/
grid-template-columns: repeat(3, 1fr);/*列*/
grid-template-areas:
'lt . rt'
'lc cc rc'
'lb . rb';
}
.lt-dot {
grid-area: lt;
}
.rt-dot {
grid-area: rt;
}
.lc-dot {
grid-area: lc;
}
.cc-dot {
grid-area: cc;
}
.rc-dot {
grid-area: rc;
}
.lb-dot {
grid-area: lb;
}
.rb-dot {
grid-area: rb;
}
点状样式(dot/red)
.dot {/*黑点*/
display: inline-block;
width: 25px;
height: 25px;
border-radius: 50%;
background-color: #1759af;
}
.red {/*红点(继承黑点属性)*/
background-color: rgb(162, 0, 211);
}
偏移+旋转面
1面(前) 前移 50%边长
6面(后) 后移 50%边长
2面(左) 左移 50%边长 + Y 90deg
3面(右) 右移 50%边长 + Y 90deg
5面(上) 上移 50%边长 + X 90deg
4面(下) 下移 50%边长 + X 90deg
.first-face {
transform: translateZ(60px);
}
.second-face {
transform: translateX(-60px) rotateY(90deg);
}
.third-face {
transform: translateX(50%) rotateY(90deg);
}
.forth-face {
transform: translateY(50%) rotateX(90deg);
}
.fifth-face {
transform: translateY(-50%) rotateX(90deg);
}
.sixth-face {
transform: translateZ(-60px);
}
效果图
加点动效(CSS_hover)
.wrap:hover {
transform: rotateX(300deg) rotateY(0deg) rotateZ(100deg) !important;
transition: transform 2s;
}
JS实现随机点数
<script>
let wrap = document.querySelector('.wrap')
let rotateX = 0 // 初始化旋转角度
let rotateY = 0
let rotateZ = 0
wrap.onclick = function () {
let x = Math.floor(Math.random() * 10) - 5 //随机数,范围是-5到5
let y = Math.floor(Math.random() * 10) - 5
let z = Math.floor(Math.random() * 10) - 5
rotateX += x * 90
rotateY += y * 90
rotateZ += z * 90
wrap.style.transform = `rotateX(${rotateX}deg) rotateY(${rotateY}deg) rotateZ(${rotateZ}deg)`
}
</script>
暂时还不会计算旋转后的点数显示
等有思路了继续更新
页面circle加载动画
HTML
<div class="container">
<div class="circle"></div>
<span>loding......</span>
</div>
CSS
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
width: 100%;
height: 100vh;
/* border: 10px solid red; */
}
.container {
position: relative;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
/* border: 10px solid rgb(0, 132, 255); */
background-color: black;
}
/* 背景彩色圆圈 */
.circle {
position: absolute;
width: 200px;
height: 200px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
/* border: 10px solid rgb(0, 255, 170); */
background-image: linear-gradient(
0deg,
rgb(0, 255, 170),
rgb(0, 17, 255),
rgb(255, 0, 255)
);
/* !!!动画!!! */
animation: rotate 2s linear infinite;
}
/* 模糊 */
.circle::before {
content: '';
position: absolute;
width: 200px;
height: 200px;
border-radius: 50%;
/* border: 10px solid rgb(0, 255, 170); */
background-image: linear-gradient(
0deg,
rgb(0, 255, 170),
rgb(0, 17, 255),
rgb(255, 0, 255)
);
filter: blur(35px);
}
/* 黑圈 */
.circle::after {
content: '';
position: absolute;
width: 180px;
height: 180px;
border-radius: 50%;
background-color: black;
}
/* 文字 */
span {
position: absolute;
color: rgb(255, 255, 255);
}
重点
animation: rotate 2s linear infinite;
/* 动画 */
@keyframes rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
遗漏点
元素区分
块元素 div / p / h / ul / li
行内元素 a / span /br
行内块元素 img / input / td
高度塌陷
就是外边距margin塌陷
只会发生在垂直方向,只出现在块级元素上
解决:子绝父相
浮动塌陷
元素一旦浮动后,脱离标准流,朝着向左或右方向移动,直到自己的边界紧贴包含块(一般是父元素)或者其他浮动元素的边界为止
clear
div -> display:float
span //float: left
span //若未设置高度,则span浮动于父元素上方,产生高度塌陷
span
span
span
p -> clear: both
div
创建BFC
div -> display:float / overflow: hidden/auto
span //float: left
span
span
span
span
div
伪元素(!最推荐!)
div class=clearfix 父元素
.clearfix::after{
content: '' //设置为空元素
display: block //设置为块级元素
clear: both //clear清除浮动
}
三角形
w:0
h:0
border: 250px solid transparent
border-方向-color:颜色
固定宽高比
需要父元素
宽高比=4:3示例
w:100% //为父元素100%
h:0
padding:0
padding-bottom:75% //为父元素75%
超出省略
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
渐变边框
.box {
width: 100px;
height: 100px;
border: 8px solid transparent; /*8px的透明边框*/
border-radius: 12px; /*圆角*/
background-clip: padding-box, border-box;/*background-clip 设置元素的背景是否延伸到边框、内边距盒子、内容盒子下面。背景延伸至边框外沿(但是在边框下层)且背景延伸至内边距(padding)外沿。不会绘制到边框处。*/
background-origin: padding-box, border-box;/*背景图片的摆放以 border padding 区域为参考*/
background-image:
linear-gradient(to right, #fff, #fff),
linear-gradient(135deg, #f00, #ff0, #f0f);
}
响应式设计
一些概念
DPR 设备像素比 =物理像素(分辨率) / 逻辑像素(机型长宽)
PPI 每英寸能放多少个像素点(一种影像指标) ‘1英寸(1in)=2.54cm'
em/rem
字体(font-size)适配单位
r(root)em
根据根元素HTML设置字体大小(如网页端1rem=16px)
em
继承父的font-size,向上查找直到根(HTML)
SVG坐标系统
ViewBox
只显示画布中的指定范围,其他地区用户看不到
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 150">
//显示(0,0)开始的 宽度300px,高度150px的box区域
</svg>
ViewPort
视窗
装box的容器
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 150" width="600" height="300">
//宽度600px,高度300px的box
</svg>
preserveAspectRatio
对齐方式
x轴
xMin:视窗左对齐
xMid:视窗中心对齐
xMax:视窗右对齐y
y轴
yMin:视窗上对齐
yMid:视窗中心对齐
yMax:视窗下对齐
meet 保持宽高比,填满容器(保证box全可见)
slice 保持宽高比,填满容器(保证视窗不留白)
none 改变宽高比,填满容器
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 300 150"
width="600" height="300"
preserveAspectRatio="xMaxyMax meet"
//preserveAspectRatio="none">
//右下对齐,保证box全可见下填满容器
</svg>
prelode 预处理器()
可以通过预处理器生成css程序
代码最终会转化成css来运行(浏览器只识别css)
css的痛点
1.重复代码
2.无法定义变量
3.无专门的作用域和嵌套
Scss
Sass使用Ruby语法 : 没有花括号,没有分号,具有严格的缩进
基础使用
pnpm install -D sass sass-loader
语法
define.scss (一般放在src中的styles文件夹中)
$--primary-color: #123456;
$white-color:$--primary-color-green !default;//这个默认值的优先级降到了最低,当没有其它地方赋值时候,才会选择默认值
vue组件
<style scoped lang="scss">
@import '@/styles/define.scss';
.box{
color:$--primary-color;
background-color:$white-color;
}
</style>
@mixin
可以定义一段代码作为模板样式
@mixin border-radius($radius: 5px, $borderRadius: 8px) {//可以接收传入的参数
border: {
radius: $radius;
top: $borderRadius solid #ff0;
bottom: $borderRadius solid #f00;
left: $borderRadius solid #00f;
right: $borderRadius solid #888;
}
}
@include border-radius(5px, 1px);//传入参数,返回计算好的样式
@extend
继承其它代码段
@mixin btn($width: 50px, $height: 20px, $font-size: 16px) {
width: $width;
height: $height;
font-size: $font-size;
text-align: center;
line-height: $height;
@include border-radius(5px, 1px);
&:hover {
opacity: 0.8;
cursor: pointer;
}
}
.btn {
@include btn(80px, 30px, 12px);
margin: {
top: 10px;
}
}
.btn-primary {
@extend .btn;//继承到了btn的样式
background-color: $light-blue;
color: $fontColor;
}
Vite配置scss
配置vite.config.ts
import { fileURLToPath } from 'url'
export default defineConfig({
plugins: [vue()],
css: {
preprocessorOptions: {
scss: {
additionalData: '@import "@/styles/define.scss";',
javascriptEnabled: true,
},
},
},
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
},
},
})
less
易上手
特点:嵌套、变量、运算、混入、映射
嵌套
注意点:hover绑定用&,&指向父级选择器
&:hover
定义变量
style.less
@mainColor: #fff;
@smallFontSize: 12px;
.box{
color: @mainColor;
font-size: @smallFontSize;
}
运算
px转rem(先挖个坑)
混入
基本
传参
混入和映射结合
弥补less中不能自定义函数的缺陷
.box_size {
width: 100px;
height: 100px;
}
.box1 {
width: .box_size()[width];//选择器对象后跟[]
}
也可以当作自定义函数来使用
.box{
width:.pxToRem(100)[result];//给pxTorem传入100使用计算完返回的值
font-size:pxToRem(18)[result];
}
偏向py,来自Node.js社区
项目中z-index的规划设计
技术规范:夹层模型
整个结构分为APP层和页面组件层。APP只有一个,但页面有很多。
1~999:都是页面内比较正常的元素
1000~1999:弹窗的灰色遮罩背景之类的组件,或者是能够遮住全屏的加载动画
2000~2999:弹窗面板,比如突然弹出来一个界面提示框,登录框、警告框之类的
3000~3999:页面鼠标交互层:比如在这个界面,会有一个鼠标点击一下就能让屏幕上多出来一个小桃心的上浮动画,这个小桃心就可以用绝对定位一个div来实现。但他的z-index必须很高,比弹窗组件还要高。
有了界面层,其实还应该有个全局的APP层,APP层是完全高于界面层的一种层。和界面一样,也有遮罩层、弹窗面板层和鼠标交互层。为了方便记忆,直接设定APP层为四位数上万。
也就是10000~~19999,20000~~29999,30000~39999。
值得注意的是,该模型中不仅有向上的考虑,还有0以下的考虑
可以设定一个页面背景层,让z-index:-1
然后再设计一个APP通用背景层,z-index:-2。
总结
1000以内都是正常页面,上千级别是页面级别的东西,上万级别是APP级别的东西。
1xxx+是弹窗背景,2xxx+是弹窗,3xxx+是鼠标交互层。
JS
var/let/const区分
作用域
var 和 let 的作用域规则一样
函数外,是全局执行上下文,函数里,是当前函数执行上下文。//声明的变量的作用域只能是全局或者整个函数块的。
重复声明
var 允许,let/const不允许
function test() {
var a = 3;
var a = 4;
console.log(a) // 4
}
let是块级作用域
const只能在声明它们的块级作用域中访问
const/let在块级作用域外无法访问内部变量!
if(true){
const a=1;
}
console.log(a)
绑定全局变量
在全局环境声明变量,var会在全局对象里新建一个属性,let/const不会
var foo = 'global'
let bar = 'global'
console.log(this.foo) // global
console.log(this.bar) // undefined
此时let定义的变量实际在test 函数的作用域链上
变量提升与暂存死区
上述代码的例子中
var例子就是变量提升,const/let的报错就是暂时性死区
代码的执行原理
创建->初始化->赋值
var 声明的变量在执行上下文创建阶段就会被「创建」和「初始化」,因此对于执行阶段来说,可以在声明之前使用。
let 声明的变量在执行上下文创建阶段只会被「创建」而不会被「初始化」,因此对于执行阶段来说,如果在其定义执行前使用,相当于使用了未被初始化的变量,会报错。
let 与 const 异同
唯一区别就在于 const 声明的是一个只读变量,声明之后不允许改变其值。
因此,const 一旦声明必须初始化,否则会报错。
DOM
DOM将HTML上的标签转化成JS对象
事件捕捉
作为第一阶段
一般对于计算机而言
方便计算机找到精准的元素
事件捕获
作为第二阶段
一般对于开发者而言
方便来做一些事件代理的功能
图片懒加载
基础
当发生滚动事件时调用 遍历 事件
加载图片其实就是给img标签src属性赋值为本来的地址,那么此时图片便会请求加载渲染出来。
<img data-src="img/1.jpg src="img/0.png alt="xxX" /> //img/0.png为加载时图片
<img data-src="img/2.jpg src="img/0.png alt="xxX" />
<img data-src="img/3.jpg src="img/0.png alt="xxX" />
<img data-src="img/4.jpg src="img/0.png alt="xxX" />
<img data-src="img/5.jpg src="img/0.png alt="xxX" />
懒加载
//获取全部img标签
var imgs = document.getElementsByTagName("img");
window.addEventListener("scroll",(e)=>{
//当发生滚动事件时调用 遍历 事件
ergodic();
});
function ergodic(){
// 遍历每一张图
for(let i of images){
//判断当前图片是否在可视区内
if(i.offsetTop<= window.innerHeight + window.scrollY){
//获取自定义data-src属性的值
let trueSrc=i.getAttribute("data-src");
//把值赋值给图片的src属性
i.setAttribute("src", truesrc);
}
}
//预先执行一次
ergodic();
}
offsetTop 为元素距离顶部的距离;
window.innerHeight 为当前窗口的高度;
window.scrollY 为滚动距离;
第二种计算方法
window.addEventListener("scroll",(e)=>{
ergodic();
})
function ergodic(){
for(let i of images){
//计算方式和第一种方式不同
if(i.getBoundingclientRect().top< window.innerHeight){
let truesrc =i.getAttribute("data-src");
}
i.setAttribute("src",truesrc);
}
ergodic();
}
getBoundingClientRect().top 为元素相对于窗口的位置;
window.innerHeight 为当前窗口的高度;
优化
基础方法的缺点:一当发生滚动事件时,就产生大量的循环和判断操作判断
IntersectionObserver
这是浏览器内置的一个API,实现了监听window的scroll事件、判断是否在视口中以及节流三大功能。
let img = document.getElementsByTagName("img");
const observer = new IntersectionObserver(changes => {
//changes 是被观察的元素集合
for(let i = 0, len = changes.length; i < len; i++) {
let change = changes[i];
// 通过这个属性判断是否在视口中
if(change.isIntersecting) {
const imgElement = change.target;
imgElement.src = imgElement.getAttribute("data-src");
observer.unobserve(imgElement);
}
}
})
Array.from(img).forEach(item => observer.observe(item));
内存管理
申请->使用->释放(垃圾回收器(GC))
交给JS(V8)引擎来处理
V8基础
闭包
最早实现闭包的语言
闭包 = 函数+可以访问的外层作用域
var name ="why
var age = 18
var height = 1.88
var address="广州市"
var intro ="了解真相,你才能获得真正自由!"
function foo(){
var message = "Hello World"
console.log(message,name, age, height, address, intro)
}
原型链
原型(prototype)
每个 !!!函数!!! 都有一个prototype属性,称之为原型
作用
//存放一些属性和方法
//在JS中实现继承
例子
const arr = new Array(1,2,3)
arr.reverse() //翻转
arr.sort() //排序
其中,reverse/sort就是存在于原型上的方法
__proto__:
每个 !!!对象!!! 都有
作用
__proto__这个属性指向它的原型对象
const arr = new Array(1,2,3)
arr.reverse() //翻转
arr.sort() //排序
console.log(arr.__proto__ === Array.prototype) //true 都指向prototype原型
原型链图解
proto指向原型对象,原型对象也是对象,对象的proto指向原型对象的原型对象
这样一层一层形成的链式结构就是原型链
最顶层找不到返回null
防抖/节流
防抖
关键词:刷新
在 连续触发事件 但是设定的一段时间内,只执行最后一次操作
//ps:1000毫秒执行的事件,中途再次触发事件会导致重新开始执行
应用场景
搜索框搜索输入
文本编辑器实时保存
代码实现思路
//使用定时器
let timerId = null
document.querySelector('.ipt').onkeyup = function (){//键盘的弹起事件
//防抖
if(timerId !== null){//第二次执行时进入if,清除前一次setTimeout函数,向下创建新的setTimeout函数
clearTimeout(timerId)
}
timerId = setTimeout(()=>{
console.log('我是防抖')
},1000)
}
每次触发清除前一次定时器
节流
关键词:冷却
在 连续触发事件 但是设定的一段时间内,只执行一次操作
应用场景
高频事件(点击/鼠标滑动/resize/scroll)
下拉加载
视频播放记录时间
代码实现思路
//使用定时器
let timerId = null
document.querySelector('.ipt').onmouseover = function (){//键盘的弹起事件
//节流
if(timerId !== null){//第二次执行时进入if,结束当前函数function函数,不执行下面的setTimeout,但是第一次的setTimeout还在执行队列里
return
}
timerId = setTimeout(()=>{
console.log('我是节流')
timerId = null
},1000)
}
等定时器执行完毕,才开启定时器
功能实现
页面预加载
本文实现了
1.预加载转圈动画+加载完毕销毁组件
2.开屏蒙版特效(after资源加载完毕)
3.主页背景图模糊+缩放动画(after资源加载完毕)
代码结构
HTML
<!-- 加载动画 -->
<div class="svg">
<div class="container">
<div class="circle"></div>
<span>loding......</span>
</div>
</div>
门板
<!-- 门板 -->
<div class="left"></div>
<div class="right"></div>
主页面
<!-- 主页面 -->
<img class="page" src="https://haowallpaper.com/link/common/file/previewFileImg/718a61f6cd6efa803ca87eb743fec045718a61f6cd6efa803ca87eb743fec045" alt="" />
JS
预加载工具
<script src="http://libs.baidu.com/jquery/1.8.3/jquery.min.js"></script>
动态更新
<!-- JS动态更新 -->
<script>
let left = document.querySelector('.left') //左门
let right = document.querySelector('.right')//右门
let page = document.querySelector('.page') //获取图片对象
$(window).on('load', function () {
$('.svg').animate(
{
opacity: 0,
},
500
)
setTimeout(function () {
$('.svg').remove()
//remove组件loding后执行
setTimeout(function () {
//门板开屏动态
left.style.transform = `translateX(-60vw)`
right.style.transform = `translateX(60vw)`
//模糊/放缩背景图片效果
page.style.animation = `blur-to-clear 2s cubic-bezier(0.62, 0.21, 0.25, 1) 0s 1
normal backwards running,scale 2s cubic-bezier(0.62, 0.21, 0.25, 1) 0s 1 both`
}, 200)
}, 500)
})
</script>
CSS
全局配置
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
margin: 0;
padding: 0;
/* 取消滚动条 */
overflow: hidden;
}
动画函数
/* 动画 */
@keyframes rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
/* 模糊动画 */
@keyframes blur-to-clear {
0% {
filter: blur(35px);
}
100% {
filter: blur(0px);
}
}
/* 图片大小变化动画 */
@keyframes scale {
0% {
transform: scale(1.5);
}
100% {
transform: scale(1);
}
}
包裹加载的样式svg(loding后去除)
.svg {
z-index: 999;
position: absolute;
width: 100vw;
height: 100vh;
background-color: black;
}
主页背景
img.page {
position: relative;
display: block;
margin: 0;
padding: 0;
box-sizing: border-box;
width: 100vw;
height: 100vh;
min-width: 1080px;
transition: opacity 1s;
/* 背景图片变化动画(已存入JS) */
/* animation: blur-to-clear 2s cubic-bezier(0.62, 0.21, 0.25, 1) 0s 1
normal backwards running,
scale 2s cubic-bezier(0.62, 0.21, 0.25, 1) 0s 1 both; */
}
加载圆圈样式
详细拆分见文章“页面circle加载动画”
.container {
position: relative;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
/* border: 10px solid rgb(0, 132, 255); */
background-color: rgb(30, 30, 30);
}
.circle {
position: absolute;
width: 200px;
height: 200px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
/* border: 10px solid rgb(0, 255, 170); */
background-image: linear-gradient(
0deg,
rgb(0, 255, 170),
rgb(0, 17, 255),
rgb(255, 0, 255)
);
/* 动画 */
animation: rotate 2s linear infinite;
}
/* 模糊 */
.circle::before {
content: '';
position: absolute;
width: 200px;
height: 200px;
border-radius: 50%;
/* border: 10px solid rgb(0, 255, 170); */
background-image: linear-gradient(
0deg,
rgb(0, 255, 170),
rgb(0, 17, 255),
rgb(255, 0, 255)
);
filter: blur(35px);
}
/* 黑圈 */
.circle::after {
content: '';
position: absolute;
width: 180px;
height: 180px;
border-radius: 50%;
background-color: rgb(30, 30, 30);
/* filter: blur(35px); */
}
span {
position: absolute;
color: rgb(255, 255, 255);
}
开屏门板
.left {
z-index: 998;
position: absolute;
width: 50vw;
height: 100vh;
background-color: rgb(30, 30, 30);
transition: transform 1s;
transform-origin: center center;
}
.right {
z-index: 998;
position: absolute;
width: 50vw;
height: 100vh;
left: 50vw;
background-color: rgb(30, 30, 30);
transition: transform 1s;
transform-origin: center center;
}
浏览器渲染流程
通过HTTP拿到html资源
浏览器(Browser)的两种引擎:
渲染引擎:加载页面
根据HTML生成DOM树结构
获取CSS资源,构建CSS OM树
计算最终页面排版
推断部分整体并为一个图层(渲染效率会更高)
JavaScript引擎:
V8引擎 为例子
JS本质是一段文本,需要解释器才能运行
引擎将js词法语法解析(Parser)转化成为AST树
通过Ignition转化为字节码(以此来在虚拟机中运行)
如果虚拟机(virtual)发现有热点代码(Hot Function)
会反馈(feedback)给Turbofan(涡轮)生成优化后的机器码,性能会更高
如果Turbofan发现数据类型不对,会让Ignition继续去优化(deoptimize)
所以尽量不要改变JS类型变量的类型
Vue3
回车触发
这里直接写vue框架的写法
<template>
<div>
<input type="text" @keyup.enter="handleSubmit" />
<!-- 其他表单元素 -->
</div>
</template>
<script>
handleSubmit() {
// 处理回车键触发的事件逻辑
// 例如提交表单、搜索数据等操作
console.log('回车键被按下');
}
</script>
路由跳转
单HTML实现
<RouterLink to="/introduce" class="btn"></RouterLink>
<router-link to="/">
<router-link :to="{name:'home'}">
<router-link :to="{path:'/home'}"> //name,path都行, 建议用name
<router-link :to="{name:'home', params: {id:1}}"> //带参
JS实现
$ router和 $ route的区别
$router : 是路由操作对象,只写对象
$route : 路由信息对象,只读对象
query相当于GET请求,页面跳转的时候,可以在地址栏看到请求参数
params相当于POST请求,参数不会在地址栏中显示
v-for,使数组每一项跳转相应页面
文章类路由设计
{
path: '/article',
component: () => import('@/views/Article/components/ArticleList.vue'),
},
{
path: '/article/:id',
name: 'article',
component: () => import('@/views/Article/components/ArticleDetail.vue'),
},
粗学React
vite脚手架搭建框架
react组件的两种创建方式:函数组件、类组件
JSX模式
主文件
入口文件index.js
import ReactDOM from 'react-dom/client'
import App from './App.js'
const root = ReactDOM.creatRoot(document.getElementById('root'));//创建ReactDOMRoot实例
root.render(//通过render渲染根组件
<React.StrictMode>//react严格模式
<App />
</React.StrictMode>
)
App.js
import
function App(){
return(//JSX语法,单行可不用 //!!!JSX模式必须只能有一个根元素!!!
<>//下面的()可以单行省略,多行如果不用(),则用幽灵标签包裹JSX语法
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
</header>
</div>
</>//需要标签闭合
);
}
export default App;
函数组件
function App(){
const divContent = '内容'
const divTitle = '标题'
//闭包
return (
<div title={divTitle}>
{divContent}
</div> //title不加“”/且为单个花括号 / 显示:“标签内容”
)
}
function App(){
//const divContent = '内容'
const divTitle = '标题'
const flag = true
let divContent = ''
if(flag){
divContent = <span>flag为true</span>//flag为true
}else{
divContent = <p>flag为false</p>//flag为false
}
return (
<div title={divTitle}>
{divContent}
</div>
)
}
列表渲染
function App(){
const list = [
{ id:1, name:'a'},
{ id:2, name:'b'},
{ id:3, name:'c'}
]
const listContent = list.map(item=>(
<li key={item.id}>{item.name}</li>
))
return (
<ul>{listContent}</ul>
)
}
export deafult App;
template?
const listContent = list.map(item=>(
<Fragment key={item.id}> //其实等价于<></>
<li>{item.name}</li>
<li>-----------</li>
</Fragment>
))
事件处理
function App(){
function Click(e){
clg('点击了按钮',e)
}
return (
<button onClick={Click}>按钮</button>
)
}
export deafult App;
状态管理(useState)
import {useState} from "react"
function App(){
function Click(e){
clg('点击了按钮',e)
}
return (
<button onClick={Click}>按钮</button>
)
}
export deafult App;
网络
HTTP/HTTPS
超文本传输协议
是客户端(用户)和服务端(网站)之间请求和响应的标准
到服务器上的指定端口(默认为80)
请求
响应
content-type 是这次请求携带的数据的类型:
application/x-www-form-urlencoded 表示数据被编码成以'&'分隔的键-值对,同时以'='分隔键和值
application/json: 表示是一个json类型
text/plain: 表示是文本类型
application/xml: 表示是xml类型
multipart/form-data: 表示是上传文件
content-length 文件的大小长度
keep-alive
http是基于TCP协议的,但是通常在进行一次请求和响应结束后会立刻中断
在http1.0中,如果想要继续保持连接
浏览器需要在请求头中添加 connection:keep-alive
服务器需要在响应头中添加 connection:keey-alive
当客户端再次放请求时,就会使用同一个连接,直接一方中断连接
在http1.1中,所有连接默认是 connection: keep-alive的
不同的Web服务器会有不同的保持 keep-alive的时间
Node中默认是5s钟
响应状态码
信息响应 (100-199)
成功响应 (200-299)
200:成功
201:post请求,创建了新的资源
重定向响应(300-399)
301:请求资源的URL已经修改,响应中会给出新的URL
客户端错误(400-499)
400:客户端错误
401:未携带身份信息
403:无权限
404:找不到资源
服务端错误(500-599)
500:服务器无法处理该问题
503:当前服务器不可用
Promise
三种状态:待定(pending 初始)
已兑现(fulfilled 成功)
已拒绝(rejected 失败)
let p1 = new Promise((resolve, reject) => {
resolve()
})
p1.then(() => {
console.log('p1 fulfilled')
}).catch(() => {
console.log('p1 rejected')
})
let p2 = new Promise((resolve, reject) => {
reject()
})
p2.then(() => {
console.log('p1 fulfilled')
}).catch(() => {
console.log('p2 rejected')
})
/*
output:
p1 fulfilled
p2 rejected
*/
传参数
let p = new Promise((resolve, reject) => {
resolve('这是「值」情况')
})
p.then((res) => {
console.log(res) /// output: 这是「值」情况
})
let p1 = new Promise((resolve, reject) => {
resolve({ msg: '这是「普通对象」情况' })
})
p1.then((res) => {
console.log(res) // output: { msg: '这是「普通对象」情况' }
})
项目文件结构规划
原则
文件语义一致
单一出入口
公共文件以绝对路径的方式从根目录引用
通用
├── public/ //与业务逻辑无关的静态资源
│ ├── index.html
│ └── favicon.ico
├── src/
│ ├── assets/ //静态资源文件
│ ├── components/ //应用程序的公共组件,一个组件通常由 .vue 文件组成,其中包含了模板、样式和逻辑
│ ├── router/ //路由
│ ├── store/ //状态管理工具
│ ├── views/ //存放应用程序页面组件
│ ├── App.vue //应用程序的整体布局和结构
│ └── main.js //入口文件,初始化 Vue3 应用程序和配置
├── tests/ //存放测试文件(可选)
├── .gitignore //指定 Git 版本控制系统忽略的文件和目录
├── babel.config.js //配置 Babel,指定需要使用的 Babel 插件和预设(可选)
├── package.json //配置文件
├── README.md //说明
└── vue.config.js //自定义 Vue CLI 的默认配置,可修改输出目录、配置代理服务器、添加自定义插件等
单页面
project
│ .browserslistrc
│ .env.production
│ .eslintrc.js
│ .gitignore
│ babel.config.js
│ package-lock.json
│ package.json
│ README.md
│ vue.config.js
│ yarn-error.log
│ yarn.lock
│
├─public
│ favicon.ico
│ index.html
│
///// src /////
|-- src
|-- components
|-- input
|-- index.js
|-- index.module.scss
|-- pages
|-- seller
|-- components
|-- input
|-- index.js
|-- index.module.scss
|-- reducer.js
|-- saga.js
|-- index.js
|-- index.module.scss
|-- buyer
|-- index.js
|-- index.js
多页面
my-vue-test:.
│ .browserslistrc
│ .env.production
│ .eslintrc.js
│ .gitignore
│ babel.config.js
│ package-lock.json
│ package.json
│ README.md
│ vue.config.js
│ yarn-error.log
│ yarn.lock
│
├─public
│ favicon.ico
│ index.html
│
///// src /////
└─src
├─apis //接口文件根据页面或实例模块化
│ index.js
│ login.js
│
├─components //全局公共组件
│ └─header
│ index.less
│ index.vue
│
├─config //配置(环境变量配置不同passid等)
│ env.js
│ index.js
│
├─contant //常量
│ index.js
│
├─images //图片
│ logo.png
│
├─pages //多页面vue项目,不同的实例
│ ├─index //主实例
│ │ │ index.js
│ │ │ index.vue
│ │ │ main.js
│ │ │ router.js
│ │ │ store.js
│ │ │
│ │ ├─components //业务组件
│ │ └─pages //此实例中的各个路由
│ │ ├─amenu
│ │ │ index.vue
│ │ │
│ │ └─bmenu
│ │ index.vue
│ │
│ └─login //另一个实例
│ index.js
│ index.vue
│ main.js
│
├─scripts //包含各种常用配置,工具函数
│ │ map.js
│ │
│ └─utils
│ helper.js
│
├─store //vuex仓库
│ │ index.js
│ │
│ ├─index
│ │ actions.js
│ │ getters.js
│ │ index.js
│ │ mutation-types.js
│ │ mutations.js
│ │ state.js
│ │
│ └─user
│ actions.js
│ getters.js
│ index.js
│ mutation-types.js
│ mutations.js
│ state.js
│
└─styles //样式统一配置
│ components.less
│
├─animation
│ index.less
│ slide.less
│
├─base
│ index.less
│ style.less
│ var.less
│ widget.less
│
└─common
index.less
reset.less
style.less
transition.less
跨端方案
视口viewport
可以看到的区域就是视口(不包括浏览器的UI界面)
fixed是相对于视口来定位的
移动端分为三种情况
布局视口(layout viewport)
默认宽度为980px
视觉视口(visual layout)
用户移动端能看到的界面
也就是显示在可见区域的视口
理想视口(ideal layout)
布局视口刚好等于视觉视口
设置viewport
移动端适配方案
百分比:很难统一,使用少
rem+动态font-size:
媒体查询
弊端:设备太多,需要大量媒体查询,维护很难