一、基于rem单位的屏幕等比例缩放
1、什么是rem
rem是浏览器描述长度的单位,是相对于 html
的字体大小的单位,1rem = html 根节点上1个字符的宽度。
2、rem的作用
使用 rem
单位设置的元素尺寸,会在不同的设备屏幕宽度下(如:手机屏幕和平板屏幕)等比例缩放。
3、rem的应用场景
当页面元素需要在不同屏幕宽度下保证元素的比例大小不变时,则可以使用 rem。
4、使用方法
- 确立参考标准,定义标准设备的屏幕宽度和字体大小。
- 比例公式(等式左右两边比例尺相同,从而达到等比例缩放的目的)= 标准屏幕宽度 / 标准字体大小 = 新的屏幕宽度 / 新的屏幕字体大小。
- 将页面样式中的
px
单位换算并替换为rem
,方法是?
rem = 元素的尺寸 / 标准字体大小 - 绑定窗口的
resize
和load
事件,触发事件时计算出新的屏幕宽度时的字体大小,来设置html
的字体大小。
5、浏览器的默认字体
通常浏览器的默认最小字体是12px,最大字体是16px。
6、代码示例
自适应屏幕分辨率:
<!DOCTYPE html>
<!-- 设置默认字体大小,所选择的参考标准字体大小 -->
<html lang="en" style="font-size: 20px;">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
body {
margin: 0;
}
.box {
background-color: #f00;
/* width: 300px;
height: 300px; */
/* 3. 根据标准字体大小计算rem值 */
width: 15rem;
height: 15rem;
}
</style>
</head>
<body>
<div class="box"></div>
</body>
<script>
const html = document.querySelector('html')
// 1. 我们定义 标准屏幕宽为 600px 标准字体大小为 20px;
// 2. 计算新的屏幕尺寸下的新的字体大小
let newFontSize = window.innerWidth / (600 / 20)
// 重新计算字体大小
function resize() {
let newFontSize = window.innerWidth / (600 / 20)
console.log(newFontSize);
// 设置html根节点的字体大小
html.style.fontSize = `${newFontSize}px`;
}
// 3. 绑定窗口尺寸变化事件和页面加载事件
window.addEventListener('resize', resize)
window.addEventListener('load', resize)
</script>
</html>
二、元素的固定宽高比和等比例缩放
1、如何按比例设置元素的宽高(原理)
- 一个父元素中的第一个子元素,其padding-top的百分比大小是参考的父元素的宽度。
- 例如: padding-top: 25%,则子元素上侧内边距就是父元素宽度的25%。
- 如此以来只要不设置父元素高度,则父元素的高度就是第一个子元素的高度,从而让父元素宽高成比例。
具体操作步骤如下:2、
- 创建一个等比例的比例盒,作为要填充元素的父元素使用
- 创建不同比例尺的维元素例如: .box_3x4::before 并在其中使用 padding-top 来达成固定高宽比
- 给所有 box 的子元素添加定位和宽高
- 给 box 填入需要固定宽高比的子元素
3、示例
<!DOCTYPE html>
<html lang="en" style="font-size: 16px">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box {
width: 100%;
background-color: #f00;
position: relative;
}
.box>* {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.box_3x4::before {
content: '';
display: block;
padding-top: 75%;
}
.box_9x16::before {
content: '';
display: block;
padding-top: 56.25%;
}
.box-container {
/* width: 300px; */
width: 18.75rem;
}
</style>
</head>
<body>
<!-- box 作为容器 将需要比例为 3x4 的元素放入其中 -->
<div class="box box_3x4">
<img src="./img/big-img.png">
</div>
<!-- 设置指定宽度,给 box 创建一个容器,并设置固定宽度即可
-->
<div class="box-container">
<div class="box box_3x4">
<img src="./img/big-img.png">
</div>
</div>
<div class="box-container">
<div class="box box_9x16">
<img src="./img/big-img.png">
</div>
</div>
</body>
<script>
const html = document.querySelector('html')
// 定义标准屏幕宽度 600 px 标准字体大小 16px
function resize() {
let newFontSize = innerWidth / (600 / 16)
html.style.fontSize = `${newFontSize}px`
}
window.addEventListener('resize', resize)
window.addEventListener('load', resize)
</script>
</html>
三、预编译工具
1、什么是预编译
编译:将写好的代码文件进行编码和翻译
预编译:预编译就是在编译环节发生之前,提前进行一次编译。其目的通常是将一个浏览器无法识别的语法提前编译成浏览器能够识别的语法。例如: css预编译 将 sass 转换为 css,js预编译 将 ts 转换成 js 等。
css的预编译:在浏览器运行脚本文件之前,进行一次编译并编译成可执行的css脚本
2、应用场景
- 项目足够大,样式足够复杂的时候可以使用预编译工具
- 项目中需要复用样式,且需要定义主题,复杂的计算等功能时,可以使用预编译工具
3、预编译工具sass
sass
工具用于对 css
进行预编译,预编译的css内容,是一个 sass/scss
文件,文件中的语法,大部分和 css
相同,有一部分是预编译的语法。
4、作用
在 css
的基础上扩展一些实用的功能。
5、市面上流行的css预编译工具
- Sass 官网:Sass: Sass Basics
- Less 官网:Getting started | Less.js
- Stylus 官网:Stylus | An expressive, robust, feature-rich CSS language built for nodejs
6、安装
- 需要先安装node.js
- npm install -g sass
7、命令行使用方法
- 语法 sass <inputPath> <outputPath>
- <inputPath> 要编译的 scss 或 sass 文件路径
- <outputPath> 编译完的 css 文件的输出路径
- sass main.scss ./css/main.css
- 监视文件变化
- 添加 --watch 标识 可以让sass自动监视文件变化 然后自动输出到指定文件
- sass --watch main.scss ./css/main.css
- 监视目录变化
- 路径参数变成 <inputDir>:<outputDir> 这样就可以监视文件夹中任一文件的变化并输出到对应文件夹
- sass --watch ./sass:./css
9、sass语法
Variables 变量
定义变量
// 语法
// $varName : value
$color: #fff;
// 访问变量
.content {
color: $color; // 直接将变量名作为属性值填在对应位置就可以了
}
Nesting 嵌套
nav {
// 嵌套 的内容 最终被解释翻译成了 子代选择器
// 这样的话 内部的样式 只有在 nav 的子代才会生效
ul {
margin: 0;
padding: 0;
list-style: none;
}
li { display: inline-block; }
a {
display: block;
padding: 6px 12px;
text-decoration: none;
}
}
使用use引入其他的sass文件
假设有个 base.scss
文件
// base.scss $color: red; .content { font-size: 12px; }
假设有个 main.scss
文件 在文件中引入 base.scss
且 两个文件在同一目录下
// main.scss // 使用@use引入外部 scss 文件 @use 'base'; // 该路径是相对路径,相对参考的是当前文件(main.scss)的路径 .box { background-color: base.$color; // 调用变量是要加上 base 命名空间(namespace) }
mixin 混合
// 定义函数 // 类似定义一个函数 // 圆括号中是参数列表 @mixin fn($primary-color: #00f, $secondary-color: #ccc) { color: $primary-color; background-color: $secondary-color; width: 200px; height: 100px; } .child1 { // 不带参数调用函数fn // 这样的话 child1 将具备 fn 的所有样式 @include fn; } .child2 { // 带参数调用函数fn // 可以给参数显示的声明参数名 // 多个参数间用逗号隔开 @include fn($secondary-color: #000, $primary-color: #fff); } .child3 { // 带参数调用函数fn // 类似js调用函数,参数按顺序传入 @include fn(red, green); }
extend 继承
// 声明父类 %parent { border: 1px solid black; font-size: 16px; font-weight: 200; font-family: "微软雅黑"; } // 声明子类 .child1 { // 通过 @extend 关键字继承父类 @extend %parent; // 子类可以有自己的属性 // 且 子类属性若和父类属性重复的话 子类属性会覆盖父类的属性 color: green; border-color: yellow; font-size: 64px; }
四则运算:
.content {
// sass 中数值可以做四则运算,但是四则运算的两个数字必须单位相同
// 或者 乘除运算可以直接和不带单位的数字进行运算(相当于放大或缩小一定的倍数)
// width: 10ex / 3ex * 10 * 5px;
// height: 15px * 5;
width: 10px + 2 * 5px;
height: ((1px + 1px) / ((50rem/25rem) * 1px)) * 5rem;
transition: (1ms / 12ms * 5s) linear forward;
transform: rotateX(30deg * 3);
}
四、bootstrap
1、布局
响应式布局:
- 响应式布局就是根据屏幕宽度,切换不同页面布局的一种布局方式,这里可以查看 bootstrap 官网在不同屏幕宽度下的表现
- bootstrap 是使用断点来完成响应式布局的
断点:
- 断点是 bootstrap 面向不同屏幕宽度,预制好的媒体查询
- 通常的讲,断点,代表的就是不同的屏幕bootstrap 中如何体现断点,在class中,添加不同断点的名称,可以采用不同断点的样式
布局容器:
- 通常是页面的根节点,使用
class="container"
来设置布局容器 - 布局容器受断点影响,可以设置不同断点上的容器,具体可查表:
网格布局:
- 将内容进行行列分布的布局方式就叫网格布局
- bootstrap中网格布局的灵魂样式就是 行:
row
,列:col - col 语法: col-{breakpoints}-{value}
例如: col-sm-3 col-lg-12
value: 范围在 1~12
bootstrap 中 一行 row 被等分为 12 分 那么col的value值代表的是占多少份
例如: col-3 此单元格占 12分之3份
2、container布局
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- 使用bootstrap的容器进行响应式布局的话,需要在head标签中加入此meta -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./css/bootstrap.min.css" />
<style>
.content {
width: 100%;
height: 100px;
background-color: violet;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
font-size: 64px;
}
</style>
</head>
<body>
<div class="container">
<div class="content">container</div>
</div>
<div class="container-sm">
<div class="content">container-sm</div>
</div>
<div class="container-md">
<div class="content">container-md</div>
</div>
<div class="container-lg">
<div class="content">container-lg</div>
</div>
<div class="container-xl">
<div class="content">container-xl</div>
</div>
<div class="container-xxl">
<div class="content">container-xxl</div>
</div>
<div class="container-fluid">
<div class="content">container-fluid</div>
</div>
</body>
</html>
3、display
<!-- 语法:
在 xs 断点下: d-{value}
xs 以上: d-{breakpoints}-{value}
-->
<!-- 当屏幕宽度小于 sm 时显示 -->
<div class="container d-block d-sm-none">小于 sm</div>
<!-- 当屏幕宽度为 md 时 显示 -->
<div class="container d-none d-sm-block d-md-none">md</div>
<!-- 当屏幕宽度大于 lg 时 显示 -->
<div class="container d-none d-md-block">大于 lg</div>
4、背景色
<h1>背景色</h1>
<!-- bg-{value} -->
<div class="bg-primary">1</div>
<h1>文本色</h1>
<!-- text-{value} -->
<div class="text-primary">hello world</div>
<h1>文本+背景色</h1>
<!-- text-bg-{value} -->
<div class="text-bg-primary">hello world</div>
5、元素大小
- 宽度:w-{value} ,value=25%,50%,75%,100%,auto
- 高度:h-{value} ,value=25%,50%,75%,100%,auto
- vw-100,vh-100相对于视口的宽高
- 内边距:p-开头,p-a设置四个方向的内边距,px-a、py-a 设置左右,上下的内边距,pt-a、pb-a、ps-a、pe-a分别设置上下左右四个方向的内边距。
- 外边距:m- 开头,与内边距同理。
- 元素的间距: vstack 竖直方向产生间距, hstack 水平方向产生间距,gap 间距的大小,(gap-x,x为一个数值)
- 边框:border border-x (x为一个数值)
6、文本
- 对齐方式:text-end,text-start,text-center
- 换行和溢出:text-nowrap(换行), overflow-scroll(有没有溢出都出现滚动条),overflow-auto(只有溢出时才会出现滚动条),overflow-hidden(溢出时隐藏溢出的部分)
- 字体大小:fs-x(x为1-5,越大越小)
- 字体加粗:fw-bolder
- 字体倾斜:fst-italic
- 行高:lh-x(x=1,sm,base,lg)
- 文本装饰线:d-inline text-decoration-underline(下划线),d-inline text-decoration-line-through(插入线),text-decoration-none(去下划线)
五、react
1、jsx 语法
jsx 语法保留了js的所有特性,在此基础上扩展了 react 的元素声明语法,例如:
// 声明一个 react-dom const element = <h1>Hello World</h1>
若 react-dom 标签有多行,可以用圆括号包裹
const element = ( <h1> Hello World </h1> )
每一给 react-dom 只能有一个根节点
const element = ( <h1> Hello World </h1> // h1 和 h2 都是根节点 这个写法是错误的 <h2> 222 </h2> )
插值
将变量插入到元素中,使用大括号 {}
const msg = 'hello world !!!' const element = <h1>{msg}</h1>
花括号内的插值部分可以写入任何有效的 js 表达式
插入html属性
直接使用引号或花括号插入表达式,如:
const styleObj = {backgroundColor: "green"} // 需要注意的是 style 属性必须用花括号来插入值 // 不是所有的html属性名都是原始名称,例如 class 应该写为 className 并采用驼峰式命名方法 而不是html的短横线 因为本质上这里的标签是js代码 const element = ( <h1 style={styleObj} className="content"> Hello World </h1> )
使用函数创建对象
// 可以使用函数创建 react-dom 对象 const element = React.createElement( 'h1', {className: 'greeting'}, 'Hello, world!' ); // 等价于 const element = ( <h1 className="greeting"> Hello, world! </h1> );
注意:jsx 中的 react-dom 内容,本质上会被 babel 翻译成 React.createElement 函数
2、创建react
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Title</title>
<!-- 1. 引入库 -->
<!-- react 需要引入 react 核心库 和 react-dom 库 -->
<script src="js/react.development.js"></script>
<script src="js/react-dom.development.js"></script>
<!-- 为了更方便书写 react 通常会使用 jsx 语法,为了支持该语法 需要引入 babel -->
<script src="js/babel.min.js"></script>
</head>
<body>
<!-- 2. 创建用于 react 渲染的根节点 -->
<div id="root"></div>
</body>
<!-- 3. 给script标签添加 type="text/babel" -->
<script type="text/babel">
// 4. 创建 root 节点对象
// 创建 react 的 root 根节点对象
const root = ReactDOM.createRoot(document.querySelector('#root'))
// 5. 渲染页面内容
// 使用 root.render 渲染页面内容
// render 函数中可以使用 jsx 语法声明页面内容
// jsx 写的内容 <h1>hello world</h1> 本质上是 js 代码
root.render(<h1>hello world</h1>)
</script>
</html>
3、元素渲染
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Title</title>
<script src="js/babel.min.js"></script>
<script src="js/react.development.js"></script>
<script src="js/react-dom.development.js"></script>
</head>
<body>
<div id="root"></div>
</body>
<script type="text/babel">
let root = ReactDOM.createRoot(document.querySelector('#root'))
// 初始化渲染
let now = new Date()
root.render((
<div>
<div className="now">当前时间:</div>
<div className="time">
{now.toLocaleString()}
</div>
</div>
))
// 渲染循环
let timer = setInterval(() => {
// 修改渲染逻辑
now = new Date()
// 渲染内容
root.render((
<div>
<div className="now">当前时间:</div>
{/* react 在每次更新的时候,都会去对比每一个 react-dom 节点
只有发现该被对比的节点有变化时(标签体变化 子节点数量变化 节点元素变化等) 才会更新节点
*/}
<div className="time">
{now.toLocaleString()}
</div>
</div>
))
}, 1000)
</script>
</html>
4、条件渲染
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Title</title>
<script src="js/babel.min.js"></script>
<script src="js/react.development.js"></script>
<script src="js/react-dom.development.js"></script>
</head>
<body>
<div id="root"></div>
</body>
<script type="text/babel">
let sex = 'male'
ReactDOM.createRoot(document.querySelector('#root')).render((
<div>
{/* 使用 && 进行短路运算 前一个表达式为true时 就显示后面表达式的内容 */}
{sex === 'male' && <div style={{color: '#00f'}}>男</div>}
{sex === 'female' && <div style={{color: 'pink'}}>女</div>}
{sex === 'other' && <div style={{color: '#ff0'}}>其他</div>}
{/* 使用三元运算符 按条件显示不同的内容 */}
{sex === 'male' ? <div style={{color: '#00f'}}>男</div> :
sex === 'female' ? <div style={{color: 'pink'}}>女</div> :
<div style={{color: '#ff0'}}>其他</div>
}
</div>
))
</script>
</html>
5、循环渲染
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Title</title>
<script src="js/babel.min.js"></script>
<script src="js/react.development.js"></script>
<script src="js/react-dom.development.js"></script>
</head>
<body>
<div id="root"></div>
</body>
<script type="text/babel">
let students = [
{
name: '张三',
sex: 'male',
age: 17
},
{
name: '李四',
sex: 'female',
age: 24
},
{
name: '小王',
sex: 'other',
age: 30
},
]
ReactDOM.createRoot(document.querySelector('#root')).render((
<div>
<ul>
{/* 循环渲染,使用一个数组的map函数 返回一个由 react-dom 充当成员形成的一个新数组
循环渲染一定要添加 key
*/}
{students.map((item,index) => <li key={index}>姓名: {item.name}; 性别: {item.sex === 'male' ? '男' :
item.sex === 'female' ? '女' : '不详'
}; 年龄: {item.age}</li>)}
</ul>
</div>
))
</script>
</html>
6、创建组件
组件具备以下特点
- 独立显示的页面内容
- 独立维护的组件状态
- 组件被当作标签使用
所以,组件是一个具备独立显示内容,独立维护状态,被当作标签使用的可复用模组
应用场景
- 可复用的页面内容,就可以考虑封装成组件
- 声明组件
- 类组件
- render函数
- 构造函数和props
- props.children
- 函数组件
- 参数props
- 函数组件没有this
react 中声明组件有两种方法
- 一种叫 类组件 另一种叫 函数组件
- 两种组件对于 react 来说是等价的