官网:https://getbootstrap.com
bootstrap
是一个用于制作页面界面的框架
框架: 提供一个标准和规范,再由开发人员自行填充内容
安装:
①官网下载:https://getbootstrap.com/docs/5.0/getting-started/download/
②npm 下载:npm i bootstrap
在html中引入css、js
<link rel="stylesheet" href="./css/bootstrap.css">
<script src="./js/bootstrap.bundle.min.js">script>
使用bootstrap的容器进行响应式布局的话,需要在head标签中加入此meta
<meta name="viewport" content="width=device-width, initial-scale=1.0">
响应式布局:根据屏幕宽度,切换不同页面布局的一种布局方式,bootstrap 是使用断点来完成响应式布局的
断点:是 bootstrap 面向不同屏幕宽度,预制好的媒体查询
通常的讲,断点,代表的就是不同的屏幕宽度
布局容器:通常是页面的根节点,使用 class="container"
来设置布局容器
布局容器受断点影响,可以设置不同断点上的容器,具体如下表:
实例代码如下:
<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>
语法:
在 xs 断点下: d-{value}
xs 以上: d-{breakpoints}-{value}
实例代码如下:
<body>
<!-- 当屏幕宽度小于 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>
</body>
float
float-start
左浮
float-end
右浮
clearfix
清除浮动
<div class="clearfix">
<div class="box bg-warning float-start"></div>
<div class="box bg-success float-start"></div>
<div class="box bg-danger float-end"></div>
</div>
position
position-{value}
value: absolute relative fixed sticky
<div style="height: 600px" class="d-flex justify-content-center">
<div style="width: 600px; height: 500px" class="border position-relative">
<div class="box bg-danger position-absolute top-50 translate-middle-y"></div>
<div class="box bg-danger position-absolute start-50 translate-middle-x"></div>
<div class="box bg-danger position-absolute end-0 top-50 translate-middle-y"></div>
<div class="box bg-danger position-absolute start-50 bottom-0 translate-middle-x"></div>
<div class="box bg-danger position-absolute start-0 top-0"></div>
<div class="box bg-danger position-absolute end-0 top-0"></div>
<div class="box bg-danger position-absolute start-0 bottom-0"></div>
<div class="box bg-danger position-absolute end-0 bottom-0"></div>
<div class="box bg-danger position-absolute start-50 top-50 translate-middle"></div>
</div>
</div>
flex
bootstrap中flex 的使用基本上就是把所有flex的属性变成了class类
<div style="height: 400px;" class="bg-success d-flex justify-content-end align-items-center align-content-center">
<div class="box bg-warning flex-grow-1"></div>
<div class="box bg-primary"></div>
<div class="box bg-primary align-self-end flex-shrink-0"></div>
<div class="box bg-primary"></div>
<div class="box bg-primary"></div>
<div class="box bg-primary"></div>
</div>
行:row
列:col
bootstrap 中 一行 row 被等分为 12 分 那么col的value值代表的是占多少份
col 语法: col-{breakpoints}-{value}
value: 范围在 1~12
纵向排列方式:在 row 上可以使用flex 的 align-items 来进行竖直方向的排列
横向排列方式:在 row 上可以使用 flex 的 justify-content 来进行水平方向的排列
单元格偏移:offset 设置单元格左侧的偏移量 数字代表的含义和 col 相同
单元格间距:添加单元格间距使用 gutter 首字母为 g。可以使用 g-{value}
或 gx-{value}
、gy-{value}
指定每一行显示多少列:row-cols-{breakpoints}-{value}
让一行显示多少列
label 与 表单元素上下排列
<div class="card p-3" style="width: 300px;">
<div class="vstack gap-2">
<div>
<label class="form-label">姓名</label>
<input class="form-control" type="text" />
</div>
</div>
label 与 表单元素左右排列
<div class="card p-3" style="width: 500px">
<div class="row">
<label class="col-3 col-form-label">姓名</label>
<div class="col">
<input class="form-control" type="text">
</div>
</div>
</div>
示例代码如下:
<div>
<label class="form-label">年龄</label>
<!-- 设置大小 -->
<input class="form-control form-control-sm" type="number" />
<input class="form-control form-control-lg" type="number" />
<!-- 禁用 disabled -->
<input class="form-control" type="number" disabled />
<!-- 只读 readonly -->
<input class="readonly form-control" type="number" readonly />
</div>
<div>
<label class="form-label">邮箱</label>
<!-- 朴素输入框 form-control-plaintext -->
<input class="form-control form-control-plaintext" type="text" readonly value="xxx@xxx.com" />
</div>
<div>
<label class="form-label">简介</label>
<!-- form-control 相关样式都可以用在文本域上 -->
<textarea disabled rows="4" class="form-control" type="text"></textarea>
</div>
单选:
<div class="row">
<label class="col-3 col-form-label">性别</label>
<div class="col">
<!-- 单选按钮 -->
<div class="form-check">
<input class="form-check-input" id="male" type="radio" name="sex" value="male">
<label class="form-check-label" for="male">男</label>
</div>
<div class="form-check">
<input class="form-check-input" id="female" type="radio" name="sex" value="female">
<label class="form-check-label" for="female">女</label>
</div>
<div class="form-check">
<input class="form-check-input" id="other" type="radio" name="sex" value="other">
<label class="form-check-label" for="other">其他</label>
</div>
</div>
</div>
多选:
form-check-inline
让选项排列在一行之中
<div class="row">
<label class="col-3 col-form-label">爱好</label>
<div class="col d-flex align-items-center">
<!-- form-check-inline 让选项排列在一行之中 -->
<div class="form-check-inline">
<input class="form-check-input" id="dlq" type="checkbox" name="hobbies" value="dlq">
<label class="form-check-label" for="dlq">打篮球</label>
</div>
<div class="form-check-inline">
<input class="form-check-input" id="tzq" type="checkbox" name="hobbies" value="tzq">
<label class="form-check-label" for="tzq">踢足球</label>
</div>
<div class="form-check-inline">
<input class="form-check-input" id="ymq" type="checkbox" name="hobbies" value="ymq">
<label class="form-check-label" for="ymq">羽毛球</label>
</div>
</div>
</div>
不确定的按钮:
需要给输入框添加 indeterminate 属性,但是该属性无法在html标签上直接添加,只能使用js添加
<input indeterminate id="indeterminate" class="form-check-input" type="checkbox">
<label class="form-check-label">不确定按钮</label>
开关按钮:
给普通的 checkbox
添加form-switch
类名即可
类似按钮的单选或多选按钮:
input 中添加 btn-check
label 中添加 btn btn-outline-{color}
注意: 为了能够勾选成功 必须给label添加for 给 input 添加id
<div class="form-check-inline">
<!-- input 中添加 btn-check -->
<input id="a" class="btn-check" type="radio" value="a" name="btn">
<!-- label 中添加 btn btn-outline-{color} -->
<!-- 注意: 为了能够勾选成功 必须给label添加for 给 input 添加id -->
<label for="a" class="btn btn-outline-warning">a</label>
</div>
<div class="form-check-inline">
<input id="b" class="btn-check" type="radio" value="bg-light" name="btn">
<label for="b" class="btn btn-outline-warning">b</label>
</div>
<body>
<div class="card p-3" style="width: 300px;">
<div>
<label class="form-label">班级</label>
<select class="form-select">
<option value="" disabled selected>请选择</option>
<option value="1">一班</option>
<option value="2">二班</option>
<option value="3">三班</option>
</select>
</div>
<div>
<label class="form-label">班级</label>
<!-- 输入框用 list 属性关联 datalist -->
<input list="clazz" type="text" class="form-control">
<!-- 通过datalist 给输入框添加待选项 -->
<datalist id="clazz">
<option value="1">一班</option>
<option value="2">二班</option>
<option value="3">三班</option>
</datalist>
</div>
</div>
</body>
表单验证:通常来说一个用户填写的表单数据都需要进行一个验证,因为用户的输入是不可信的,所以说在表单输入的时候需要对用户的输入做验证
应用场景:用户产生输入的时候
novalidate
屏蔽默认的表单提交时的验证报告,屏蔽掉自动的验证报告的目的 是为了我们自己好去控制验证报告
required
必填
pattern
正则表达式
minlength
最小长度 maxlength
最大长度
min
最小值 max
最大值
type
类型验证
<input name="name" required type="text" class="form-control">
<input name="name" pattern="[\s\S]*张三[\s\S]*" type="text" class="form-control">
<input name="name" minlength="2" maxlength="10" type="text" class="form-control">
<input name="name" min="0" max="200" type="number" class="form-control">
<input type="email" class="form-control">
通过输入框的 validity
属性 来判断用户是否输入正确
validity.valueMissing
-> required 用户没填数据时为 true
validity.patternMismatch
-> pattern 用户输入不满足正则 true
validity.rangeOverflow
-> max 用户输入超过最大值 true
validity.rangeUnderflow
-> min 用户输入小于最小值 true
validity.tooLong
-> maxlength 用户输入超出长度 不会触发 true
validity.tooShort
-> minlength 用户输入小于了指定长度 true
validity.valid
-> 输入没有问题 验证通过 true
总结表单验证:
- 添加 novalidate
- 验证所有表单项
- 设置错误信息
- 发起验证报告
- 验证通过 执行后续逻辑
自动验证
给form添加类名 was-validated 就可以开启验证效果
验证的提示需要写在被验证的输入框下面
valid-feedback
:验证通过的提示文本
invalid-feedback
:验证不通过的提示文本
手动验证
<script>
let nameInp = document.querySelector('input[name=name]')
let ageInp = document.querySelector('input[name=age]')
// 查询错误提示的元素
let nameErrTip = document.querySelector('input[name=name]~.invalid-feedback')
let ageErrTip = document.querySelector('input[name=age]~.invalid-feedback')
let btn = document.querySelector('button')
btn.addEventListener('click', () => {
// 手动通过代码进行验证
// 清空所有的 is-valid 和 is-invalid
nameInp.classList.remove('is-valid', 'is-invalid')
ageInp.classList.remove('is-valid', 'is-invalid')
// 定义一个代表验证通过的变量
let nameValid = true
if (nameInp.value.trim() === '') {
nameErrTip.textContent = '请输入姓名'
nameValid = false
} else if (nameInp.value.trim().length < 2 || nameInp.value.trim().length > 10) {
nameErrTip.textContent = '请输入2~10个字的姓名'
nameValid = false
}
let ageValid = true
if (Number(ageInp.value) < 0 || Number(ageInp.value) > 150) {
ageErrTip.textContent = '请输入0~150之间的年龄'
ageValid = false
}
nameInp.classList.add(nameValid ? 'is-valid' : 'is-invalid')
ageInp.classList.add(ageValid ? 'is-valid' : 'is-invalid')
if (nameValid && ageValid) {
// 整个表单输入正确的情况
// 可以执行后续的网络请求
console.log('验证通过');
}
})
</script>
官网:https://zh-hans.reactjs.org
react
是一个 js核心库,如同 jquery
一样,具有大量 react
生态(围绕 react
核心开发的库)
特点:
react
可以开发 桌面web页面,移动端页面,移动app,桌面app等使用cdn在html引入react
<!-- react 需要引入 react 核心库 和 react-dom 库 -->
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<!-- 为了更方便书写 react 通常会使用 jsx 语法,为了支持该语法 需要引入 babel -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
react.js 这是框架核心库,用于解析 react 语法
eact-dom.js 这个库是用于 react 元素(也就是react的文档对象模型)的创建
babel.js 这个库用来将 jsx 语法翻译为普通的 js
jsx 语法保留了js的所有特性,在此基础上扩展了 react 的元素声明语法
采用 jsx 语法 需要在 type 处加上 text/babel
声明
使用jsx创建一个react-dom对象
react-dom 是 react 封装的类似 dom 对象的对象
作用: 用于描述页面元素
const element = <h1>Hello World</h1>
若有多行标签,可以用圆括号包裹
const element = (
<div className="box">
<span>hello box</span>
</div>
)
每一个 react-dom 只能有一个根节点
const element = (
<h1>
Hello World
</h1>
// h1 和 h2 都是根节点 这个写法是错误的
<h2>
222
</h2>
)
插值
将变量插入到元素中,使用大括号{}
const msg = 'hello world !!!'
const element = <h1>{msg}</h1>
花括号内的插值部分可以写入任何有效的 js 表达式
注意:插值中写注释,必须用大括号包裹并且用多行注释
const chazhi = (
<div>
{ /*使用花括号进行插值 插值的内容可以是js表达式*/}
{'当前时间: ' + now.toLocaleString()}
</div>
)
需要注意的是 style 属性必须用花括号来插入值
不是所有的html属性名都是原始名称,例如 class 应该写为 className 并采用驼峰式命名方法 而不是html的短横线 因为本质上这里的标签是js代码
const styleObj = {backgroundColor: "green"}
const element = (
<h1
style={styleObj}
className="content">
Hello World
</h1>
)
使用函数创建对象
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
// 等价于
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
jsx 中的 react-dom 内容,本质上会被 babel 翻译成 React.createElement 函数
const fnDom = React.createElement(
// 标签名
'div',
// 标签上的属性
{id: 'myFunctionDom', className: 'my-dom', style: {width: '500px', height: '50px', backgroundColor: '#00f'}},
// 子元素数组 或 标签体字符串
[
// 此处的第三个参数就是一个普通的字符串充当 span 标签的标签体
React.createElement('span', {key: '1'}, 'hello world'),
// 若此处 createElement 第三个参数是一个数组的话,需要给元素添加 key 属性
// key 属性是一个唯一值 不重复即可
React.createElement('span', {key: '2'}, 'hello world')
]
)
渲染
root.render 函数可以渲染一个 react-dom 对象
root.render((
<div className="container">
{/* 插值的内容 若是 react-dom 对象 那么就会被页面显示出来 */}
{h1}
{box}
{element}
{chazhi}
{htmlAttr}
{fnDom}
</div>
))
初始化渲染
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)
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>
))
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 充当成员形成的一个新数组 */}
{students.map(item => <li>姓名: {item.name}; 性别: {item.sex === 'male' ? '男' :
item.sex === 'female' ? '女' : '不详'
}; 年龄: {item.age}</li>)}
</ul>
</div>
))
组件是一个具备独立显示内容,独立维护状态,被当作标签使用的可复用模组
特点:
1.独立显示的页面内容
2.独立维护的组件状态
3.组件被当作标签使用
应用场景:可复用的页面内容,就可以考虑封装成组件
类组件
声明类组件需要继承React.Component
class AComponent extends React.Component {
// 可以有组件的属性
label = 'h'
// 构造函数中包含props参数
// props 代表组件的 html 属性
// props 是只读属性
constructor(props) {
// 由于存在父类 React.Component
// 所以构造函数中应先调用super
super(props)
// render 函数中可以使用 this.props 访问此处的 props
console.log(props)
// 可以使用 props.children 代表组件标签体里的内容
console.log(props.children)
}
// 可以有组件方法
getTime() {
return new Date()
}
// 类组件中必须包含 render 方法
render() {
// render 方法必须返回一个 react-dom 对象
// 返回的 react-dom 对象用于描述组件长什么样子的
return (
<div>
{/* 组件中可以调用自己的属性和方法 */}
{this.label}: {this.getTime().getHours()}; m: {this.getTime().getMinutes()};
s: {this.getTime().getSeconds()}
<br/>
{/* 标签体的内容可以插值到 render 中 */}
{this.props.children}
</div>
)
}
}
函数组件
function BComponent(props) {
// 此处的this为 undefined
// 之所以为 undefined 是因为函数组件没有实例对象
console.log(this)
console.log(props)
// 可以在组件内声明其他函数和变量
let count = 0
function getCount() {
return count
}
// 函数组件必须返回一个react-dom对象
return (
<div>
<div>我是一个函数组件</div>
<div>{count}: {getCount()}</div>
<div>{props.children}</div>
</div>
)
}
通常指某个时刻用于描述某个对象的数据模型
class组件状态
组件的状态更新:this.setState
1.不要直接修改state,要通过setState修改
2.setState的参数不要直接依赖this.State或者this.props,应使用this.setState((state,props)=>{return{}})代替
3.setState方法是异步的,可以通过setState的第二个回调函数来执行复制成功后的代码
4.setState最终会修改this.state
若不存在组件时 更新数据的办法是 重复调用 root.render 函数
函数组件状态
在函数组件内使用 React.useState 来声明状态
useState 参数代表状态的初始值,返回值是一个数组
0 号成员是 状态的 getter 用来读取状态
1 号成员是 状态的 setter 用来赋值状态
setState 是异步的
setState 依赖自己状态的时候,使用回调函数
状态值若为对象(或数组)时,为了状态能够被修改,需要赋值一个新的对象(或数组)
生命周期
用函数来描述对象的生老病死
阶段
生命周期有哪些阶段
- 挂载
constructor()
static getDerivedStateFromProps() // https://zh-hans.reactjs.org/docs/react-component.html#static-getderivedstatefromprops
render()
componentDidMount()- 更新
static getDerivedStateFromProps(props, state)=>{[key: string]: any} 每次调用渲染函数render前调用,返回值是希望改变的状态对象
shouldComponentUpdate(props, state)=>boolean 判断是否应该更新,返回一个布尔值
render()
getSnapshotBeforeUpdate(prevProps, prevState)=>{[key: string]: any} 每次更新前调用,返回值将被传递给 componentDidUpdate 充当第三个参数
componentDidUpdate(prevProps, prevState, snapshot)- 卸载
componentWillUnmount()- 异常捕获
static getDerivedStateFromError()
componentDidCatch()
应用场景
其中 挂载和卸载的 生命周期用得比较多
constructor() 常用于初始化组件,拉取远程数据
componentDidMount() 用于页面第一次渲染完成后,查询页面元素
componentWillUnmount() 卸载组件时对事件的解绑等需要处理的事
卸载组件
root.unmount()
绑定事件的基本流程:
1.on+事件名称
2.使用花括号插值一个事件处理程序
3.获取事件对象
4.给事件处理程序传参
react 中 无法使用 return false 直接屏蔽默认事件
class组件绑定事件
类组件中普通的事件绑定无法在事件处理程序中访问this关键字
若想希望在绑定的事件函数中使用 this 来访问组件自身
则需要在类组件的事件处理程序里赋值this关键字:
1.constructor 中使用 bind
2.在绑定事件插值时使用箭头函数
3.在绑定事件插值时使用bind
constructor(props) {
super(props);
this.clickHandler = this.clickHandler.bind(this)
}
clickHandler(ev) {
console.log('click')
console.log(ev)
console.log(this)
this.setState(state => ({count: state.count + 1}))
}
<button onClick={this.clickHandler}>点击</button>
clickHandler(ev) {
console.log('click')
console.log(ev)
console.log(this)
this.setState(state => ({count: state.count + 1}))
}
<button onClick={ev => {this.clickHandler(ev)}}>点击</button>
clickHandler(ev) {
console.log('click')
console.log(ev)
console.log(this)
this.setState(state => ({count: state.count + 1}))
}
<button onClick={this.clickHandler.bind(this)}>点击</button>
函数组件绑定事件
/* 在标签添加事件 */
<button onContextMenu={contextMenuHandler}>点击</button>
/* 使用箭头函数在调用事件处理程序的时候传递参数 */
<button onContextMenu={ev => {contextMenuHandler(ev, 5)}}>点击</button>
/* react 无法直接通过 return false 屏蔽默认事件 */
<form onSubmit="return false">
<button>提交</button>
</form>
/* 事件函数 */
//事件处理程序添加参数ev,ev代表事件对象
function contextMenuHandler(ev, id) {
// 屏蔽默认事件
ev.preventDefault()
console.log('contextMenuHandler')
console.log(ev)
console.log(id)
}