青训营期间对前端技术知识的查补|豆包MarsCode AI刷题

64 阅读23分钟

前端应该关注

功能,美观,无障碍,安全,性能,兼容性,用户体验

HTML

HyperText Markup Language

HyperText:包含图片、标题、链接、表格等

Markup 语法
Markdown 语法
HTML生成DOM树

image-20241103204202336

<script setup> :

  • setup 是 Vue 3 的一个语法糖,用于简化组合式 API 的使用。
  • setup 脚本中定义的变量和函数会自动暴露给模板,无需显式返回。

DOM Tree 会形成 Render Tree

某些情况下Render会合成自己的图层

image-20241110164025028

插槽

可以在父组件中定义子组件内部的内容

默认插槽

<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 的插槽中获取的当前匹配的组件。
作用域插槽

image-20241031184452125

路由

  • 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 参数表示即将进入的目标路由。
  1. 导航守卫:

    • router.beforeEach 是 Vue Router 提供的导航守卫,用于在导航发生之前进行一些检查。
    • to 参数表示即将进入的目标路由。
  2. 获取用户状态:

    • const userStore = useLoginStore() 获取 Pinia store 实例。
    • userStore.token = localStorage.getItem('token') as unknown as string 从本地存储中获取用户的 token,并将其赋值给 userStore
  3. 检查登录状态:

    • 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 样式表

层叠--------------------------》解决冲突
样式表-》规则声明的集合-》产生冲突-》解决冲突
例如
#titleh1都作用于同一个标签上
规则集合内就会产生冲突,层叠会解决这个冲突

层叠三大规则

生效优先级

样式表来源>选择器优先级>源码位置

样式表来源

用户代理样式(浏览器默认)>用户样式表(少有)>作者样式表(developer写的)

选择器优先级

选择器

image-20241110135227594

内联 > id > class = attribute = pseudo-class > type = pseudo-element
选择器尽量少用id,!imortant(级别最高),自己的样式加载到引用库后面

简要发展史

image-20241110133653789

目前是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的情况

image-20241104160610394

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)”
对齐方式

image-20241110155405765

image-20241110155807497

image-20241110160000770

层叠上下文

对HTML元素的三维构想,基于用户界面z轴的上下排布

对于浏览器渲染过程的“渲染层(render layer)”
层叠水平

也就是层叠顺序

image-20241110164351519

z-index只能在同一个层叠上下文比较
子元素的z-index无法超过父元素的z-index顺序

定位

image-20241110163644817

grid网格布局

新的长度单位:fr

一般来说 1fr 的意思是“100%的剩余空间”, .25fr 意味着“25%的剩余空间”。当时当 fr 大于 1 的时候,则会重新计算比例来分配。

image-20241110161821264

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 的情况

响应式设计

这里 AD 都是固定的 50pxC 是占总宽度的 20%,剩余空间就可以分配给 B

.grid-container {
  grid-template-columns: 50px 1fr 20% 50px;
  column-gap: 10px;
}

image-20241110161302301

船新用法

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;
}
......

image-20241110163133135

相比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)

image-20241110201517099

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);
}

效果图

image-20241115152235630

加点动效(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加载动画

image-20241116165834762

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

image-20241102030705277

定义变量

style.less

@mainColor: #fff;
@smallFontSize: 12px;

.box{
    color: @mainColor;
    font-size: @smallFontSize;
}

运算

px转rem(先挖个坑)

混入

基本

image-20241102162529566

传参

image-20241102163610811

混入和映射结合

弥补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 函数的作用域链上

image-20241104212220166

变量提升与暂存死区

image-20241104223204685

上述代码的例子中

var例子就是变量提升,const/let的报错就是暂时性死区

代码的执行原理

创建->初始化->赋值
var 声明的变量在执行上下文创建阶段就会被「创建」和「初始化」,因此对于执行阶段来说,可以在声明之前使用。
let 声明的变量在执行上下文创建阶段只会被「创建」而不会被「初始化」,因此对于执行阶段来说,如果在其定义执行前使用,相当于使用了未被初始化的变量,会报错。

let 与 const 异同

唯一区别就在于 const 声明的是一个只读变量,声明之后不允许改变其值。
因此,const 一旦声明必须初始化,否则会报错。

DOM

DOM将HTML上的标签转化成JS对象

image-20241102174400826

事件捕捉

作为第一阶段

一般对于计算机而言

方便计算机找到精准的元素

事件捕获

作为第二阶段

一般对于开发者而言

方便来做一些事件代理的功能

图片懒加载

基础

当发生滚动事件时调用 遍历 事件

加载图片其实就是给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基础

image-20241031195651790

闭包

最早实现闭包的语言

闭包 = 函数+可以访问的外层作用域

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)
}

image-20241031205643793

原型链

原型(prototype)

每个 !!!函数!!! 都有一个prototype属性,称之为原型

作用

//存放一些属性和方法
//在JS中实现继承

例子

const arr = new Array(1,2,3)
arr.reverse()	//翻转
arr.sort()		//排序

其中,reverse/sort就是存在于原型上的方法

image-20241105213824829

__proto__

每个 !!!对象!!! 都有

作用

__proto__这个属性指向它的原型对象
const arr = new Array(1,2,3)
arr.reverse()	//翻转
arr.sort()		//排序
console.log(arr.__proto__ === Array.prototype)	//true 都指向prototype原型

原型链图解

image-20241105214143342

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资源

image-20241102171041239

浏览器(Browser)的两种引擎:

渲染引擎:加载页面

根据HTML生成DOM树结构
获取CSS资源,构建CSS OM树
计算最终页面排版
推断部分整体并为一个图层(渲染效率会更高)

JavaScript引擎

V8引擎 为例子

image-20241102171119537

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,使数组每一项跳转相应页面

image-20241120224628906

文章类路由设计

{
    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)

image-20241031210920403

请求

image-20241031215221074

响应

image-20241031215606950

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

image-20241103191251884

视觉视口(visual layout)

用户移动端能看到的界面

也就是显示在可见区域的视口

image-20241103191750724

理想视口(ideal layout)

布局视口刚好等于视觉视口

设置viewport

image-20241101151006653

移动端适配方案

百分比:很难统一,使用少

rem+动态font-size

媒体查询

弊端:设备太多,需要大量媒体查询,维护很难

image-20241103194536352

js编写动态的font-size

image-20241103214932679

lib-flexble

amfe/lib-flexible: 可伸缩布局方案