React(五) 受控组件和非受控组件; 获取表单元素的值。高阶组件(重点),Portals; Fragment组件;严格模式StrictMode

文章目录

  • 一、受控组件
    • 1. 什么是受控组件
    • 2. 收集input框内容
    • 3. 收集checkBox的值
    • 4. 下拉框select
    • 总结
  • 二、非受控组件
  • 三、高阶组件
    • 1. 高阶组件的概念 (回顾高阶函数)
    • 2. 高阶组件应用:注入props
      • (1) 高阶组件给---函数式组件注入props
      • (2) 高阶组件给---类组件注入props
      • (3) 高阶组件注入props+自己需要注入props
    • 3. 高阶组件应用:context的增强
    • 4. 高阶组件应用:登录鉴权
    • 5. 高阶组件应用:生命周期劫持
    • 总结
  • 四、 Portals
  • 五、 Fragment组件
  • 六、 严格模式StrictMode

一、受控组件

1. 什么是受控组件

当表单元素绑定value属性时,就是受控组件,此时按键盘也无法再向输入框里输入信息

若要输入信息,必须绑定onChange事件,获取输入的值,修改state,然后通过value属性将修改后的值显示到输入框里。(很像vue中的v-model)
在这里插入图片描述

2. 收集input框内容

(1) form标签上绑定onSubmit事件,当提交时,触发该事件。
(2) label标签里,htmlFor属性值为所绑定的表单属性的id
(3) 两个不同类型输入框的处理事件合并到一个函数中。e.target.name的值是input标签里的name属性。e.target.value是输入框里的值。(键值读取变量用[]包裹)。

// 提交事件
handleSubmitClick (e) {// 1.阻止默认的行为e.preventDefault()// 2.获取到所有的表单数据, 对数据进行组件console.log("获取所有的输入内容:", this.state.username, this.state.password)// 3.以网络请求的方式, 将数据传递给服务器(ajax/fetch/axios)
}// 处理input框输入
handleInputChange (e) {this.setState({[e.target.name]: e.target.value})
}// 渲染render () {const { username, password } = this.statereturn (<div><form onSubmit={e => this.handleSubmitClick(e)}><label htmlFor="username">用户:<input type="text" id="username" name='username'value={username}onChange={e => this.handleInputChange(e)} /></label><br /><label htmlFor="password">密码:<input type="password" name="password" id="password"value={password}onChange={e => this.handleInputChange(e)} /></label><br /><button type='submit'>注册</button></form></div>)}

3. 收集checkBox的值

单选框
(1) 通过checked属性设置该框是否被选中。实现数据改变页面
(2) 读取e.target.checked来获取用户的输入,判断用户点击后,checkbox是true还是false

 handleAgreeChange (e) {// 根据用户输入修改状态值this.setState({isAgree: e.target.checked})}
{/* 单选框 this.state.isAgree默认值是false */}const { isAgree } = this.state
<label htmlFor="agree"><inputid='agree'type="checkbox"checked={isAgree}onChange={e => this.handleAgreeChange(e)}/>同意协议
</label><br />

多选框
多选框就是循环遍历数据。与单选框处理逻辑类似,注意修改hobbies时,需要浅拷贝。

  hobbies: [{ value: "sing", text: "唱", isChecked: false },{ value: "dance", text: "跳", isChecked: false },{ value: "rap", text: "rap", isChecked: true }],{/* 多选框 */}{hobbies.map((item, index) => {return (<label htmlFor={item.value} key={item.value}><inputtype="checkbox"id={item.value}checked={item.isChecked}onChange={(e) => this.handleHobbiesChange(e, index)} />{item.text}</label>)})}// 注意需要浅拷贝
handleHobbiesChange (e, index) {console.log(e.target.checked, index);const hobbies = [...this.state.hobbies]hobbies[index].isChecked = e.target.checkedthis.setState({ hobbies })
}

4. 下拉框select

单选下拉框
(1)通过value属性来设置默认值,fruit: "apple",
(2) e.target.value来读取用户选了什么水果;

   {/* 下拉框 */}{/*  value={fruit} 设置默认值 */}<select value={fruit} onChange={e => this.handleFruitChange(e)}><option value="orange">橘子</option><option value="apple">苹果</option><option value="banana">香蕉</option></select>// 水果下拉框
handleFruitChange (e) {this.setState({ fruit: e.target.value })
}

多选下拉框
(1)添加multiple属性,设置多选,此时绑定的value值为 fruits: ['apple', 'banana']
(2)e.target.selectedOptions获取用户选择,具体看事件处理函数

 {/* 多选框 */}<select value={fruits} onChange={e => this.handleFruitsChange(e)} multiple><option value="orange">橘子</option><option value="apple">苹果</option><option value="banana">香蕉</option></select>
// 水果下拉多选框
handleFruitsChange (e) {const options = Array.from(e.target.selectedOptions)// options里每一项的value值是用户选择的值const values = options.map(item => item.value)this.setState({ fruits: values })// 额外补充: Array.from(可迭代对象)// Array.from(arguments)const values2 = Array.from(e.target.selectedOptions, item => item.value)console.log(values2)
}

在这里插入图片描述

总结

ElementValue propertyChange callbackNew value in the callback
<input type="text" />value="string"onCahngee.target.value
<input type="checkbox" />checked={boolean}onCahngee.target.checked
<input type="radio" />checked={boolean}onCahngee.target.checked
<textarea/>value="string"onCahngee.target.value
<select/>value="option value"onCahngee.target.value

二、非受控组件

(1) 绑定默认值不能用value,会变成受控组件。应该用defaultValue
(2) 给元素添加监听事件,只能用原生的方式; 首先需要绑定ref,然后添加监听事件addEventListener
(3) 通过this.introRef.current.value来获取输入框里的值。
(4) checkboxradio支持defaultCheckedselecttextarea支持defaultValue

export class App extends PureComponent {constructor() {super()this.state = {intro: '123456'}this.introRef = createRef()}componentDidMount () {this.introRef.current.addEventListener(...)}// 提交事件handleSubmitClick (e) {// 1.阻止默认的行为e.preventDefault()// 2.获取到所有的表单数据, 对数据进行组件console.log(this.introRef.current.value);// 3.以网络请求的方式, 将数据传递给服务器(ajax/fetch/axios)}// 渲染render () {const { intro } = this.statereturn (<div><form onSubmit={e => this.handleSubmitClick(e)}>{/* 非受控组件 */}<input type="text" defaultValue={intro} ref={this.introRef} /><button type='submit'>注册</button></form></div >)}
}

三、高阶组件

1. 高阶组件的概念 (回顾高阶函数)

(1) 高阶函数
满足这两个条件之一的就是高阶函数:
接受一个或多个函数作为输入;
输出一个函数;
比如JS中的map,filter,reduce

funcition foo(){function bar(){}return bar
}
// foo函数返回一个函数,所以这个也是高阶函数
const fn = foo()

(2) 高阶组件(Higher-Order Components) 简称HOC
高阶组件本质是一个函数(并不是组件),这个函数的参数是组件,函数的返回值是一个新组件。

// 1. 定义一个原组件
class OriginHW extends PureComponent {render () {return (<div>HelloWorld</div>)}
}
// 2. 定义一个高阶组件,接收原组件,并对原组件进行一些操作
function hoc (Cpn) {class newHW extends PureComponent {render () {return <Cpn name="why" />}}return newHW
}// 3. 调用高阶组件,这里的参数直接传原组件的名称;接收到的一个新组件
const HelloHOC = hoc(OriginHW)class App extends PureComponent {render () {return (<div>{/* 使用新组件 */}<HelloHOC /></div>)}
}

界面打印:HelloWorld;

可以看出,高阶组件对原来的组件进行了一层拦截,拦截之后就可以对组件进行一些操作,再返回组件。

高阶组件不是React API的一部分,是一种设计模式
高级组件再一些React第三方库中十分常见:
 * 比如:redux中的connect
 * 比如:react-router中的withRouter

2. 高阶组件应用:注入props

  首先定义一个高阶组件,用于给需要特殊数据的组件,注入props数据。比如某些组件需要userInfo这个数据。

src/hoc/enhancedUserInfo.js

// 定义高阶组件,给需要特殊数据的组件,注入props
function enhancedUserInfo (OriginComponent) {class NewComponent extends PureComponent {// 构造函数constructor() {super()this.state = {userInfo: {userName: 'tom',age: '18'}}}render () {return (// 通过props的方式将数据传给组件<OriginComponent {...this.state.userInfo} />)}}// 其实本质上return的是注入了props数据的<OriginComponent/>组件return NewComponent
}
export default enhancedUserInfo

(1) 高阶组件给—函数式组件注入props

App.jsx

import React, { PureComponent } from 'react'
import enhancedUserInfo from './hoc/enhancedUserInfo'
import About from './pages/About'// 增强函数式组件,props接收数据,
// funtion后面可以不写函数名,这里是为了区分增强前后,Friend与NewFriend
const NewFriend = enhancedUserInfo(function Friend (props) {return <h2>Hello--{props.userName}---{props.age}---{props.fruit}</h2>
})// App应用函数式组件
class App extends PureComponent {render () {...<NewFriend />}
}

(2) 高阶组件给—类组件注入props

src/pages/About.jsx:创建类组件About

import enhancedUserInfo from '../hoc/enhancedUserInfo'
class About extends PureComponent {render () {return (<div>{/* 没有构造函数也可以读取this.props */}<h2>About---{this.props.userName}---{this.props.age}</h2></div>)}
}
// 在导出的时候,利用高阶组件增强改类组件,让该组件收到props数据
export default enhancedUserInfo(About)

App.jsx

// App应用函数式组件
class App extends PureComponent {render () {...<About/>}
}

(3) 高阶组件注入props+自己需要注入props

在使用子组件之前,通过高阶组件可以注入一些props数据;如果在App中使用子组件时,也往里传递了数据,该怎么接收。

class App extends PureComponent {render () {return (<div>{/* fruit实际是传给了高阶组件里的NewComponent */}<NewFriend fruit={['apple', 'banana']} /><About fruit={['橘子', '火龙果']} /></div>)}
}

这里传递的fruit,实际上是传到了enhancedUserInfo里的NewComponent类中,然后再通过props的方式传给OriginComponent.
在这里插入图片描述
原组件中仍然是通过props来接收这些数据
在这里插入图片描述

3. 高阶组件应用:context的增强

照旧先创建theme-context

src/context/theme-context.js

import { createContext } from 'react'
const ThemeContext = createContext()
export default ThemeContext

App中应用子组件Product,并用Context包裹子组件,传递数据

class App extends PureComponent {render () {return (<div>{/* 使用新组件 */}<ThemeContext.Provider value={{ color: 'red', size: 20 }}><Product /></ThemeContext.Provider></div >)}
}

子组件接收context数据的方式有两种,指定context类型的只能接收一种context数据。所以一般通过consumer来接收多个context数据。之前的做法是在组件内部使用consumer:
在这里插入图片描述
这样的会让组件可读性不高,且不好维护。

利用高阶组件的做法:在高阶组件中使用consumer,然后将context数据注入原组件中。
(1) 定义高阶组件withTheme;
src/hoc/with-theme.js:

import ThemeContext from "../context/theme-context"
function withTheme (OriginComponent) {return (props) => {return (<ThemeContext.Consumer>{value => {// 通过props将context数据传给子组件return <OriginComponent {...value} />}}</ThemeContext.Consumer>)}
}
export default withTheme

(2) 高阶组件在子组件向外暴露的时候拦截一下,注入数据:

import withTheme from '../hoc/with-theme'
export class Product extends PureComponent {render () {return (// props接收数据。<div>Product---color:{this.props.color}---size:{this.props.size}</div>)}
}
export default withTheme(Product)

4. 高阶组件应用:登录鉴权

(1) 定义一个高阶组件。判断当前是否有token,有就说明登录了(登录就渲染界面),没有就没登录(没登录就返回提示信息)

src/hoc/login-auth .js

function loginAuth (OriginComponent) {// 返回一个函数式组件return (props) => {const token = localStorage.getItem('token')if (token) {      // 登录则渲染该组件return <OriginComponent />} else {      // 没登录则给出提示信息return <h2>请先登录</h2>}}
}
export default loginAuth

(2) 哪个子组件需要登录鉴权,就用高阶组件拦截一下
子组件Cart:

import loginAuth from '../hoc/login-auth'
export class Cart extends PureComponent {render () {return (<div>Cart</div>)}
}
export default loginAuth(Cart)

(3) App中使用子组件
App中设置一个state数据:isLogin,用来渲染数据的变化。

class App extends PureComponent {...login () {localStorage.setItem('token', 'tom')// 设置isLogin变量的目的是,确定登录,修改数据,能够重新调用render函数this.setState({ isLogin: true })// 如果没有isLogin,可以调用强制刷新的API,但是也不建议使用这个API// this.forceUpdate()}render () {return (<div><Cart /><button onClick={e => this.login()}>点击登录</button></div >)}
}

高阶函数里什么时候适合创建类组件,什么适合适合创建函数组件。

5. 高阶组件应用:生命周期劫持

通过生命周期来计算每个组件的挂载时间。

  export class Detail extends PureComponent {UNSAFE_componentWillMount () {this.beginTime = new Date().getTime()}componentDidMount () {this.endTime = new Date().getTime()const interval = this.endTime - this.beginTimeconsole.log(`当前页面花费了${ interval }ms渲染完成!`)}render () {...}}

抽取到高阶组件中:

// 可以对需要计算渲染时间的组件进行拦截
function logRenderTime (OriginComponent) {// 函数式组件没有生命周期,所以返回一个类组件;// 由于是直接返回这个类,所以类名可以省略 class NewComponent extends...return class extends PureComponent {UNSAFE_componentWillMount () {this.beginTime = new Date().getTime()}componentDidMount () {this.endTime = new Date().getTime()const interval = this.endTime - this.beginTimeconsole.log(`当前${ OriginComponent.name }页面花费了${ interval }ms渲染完成!`)}render () {return <OriginComponent {...this.props} />}}
}
export default logRenderTime

OriginComponent.name可以拿到组件的名字;

应用在某个组件上:

import logRenderTime from '../hoc/log_render_time'
export class Detail extends PureComponent {...
}
export default logRenderTime(Detail)

总结

高阶组件主要是方便代码的复用。
高阶组件中什么时候返回类组件,什么时候返回函数式组件,取决于是否

四、 Portals

 某些情况下,我们希望渲染的内容独立于父组件,挂载到其他位置。甚至独立于当前挂载的DOM元素中。

<!--比如当前除了root根节点,还有第二个节点。通过Portals,我们可以将内容挂载到root2中--><div id="root"></div><!-- 新节点 --><div id="root2"></div>

App.jsx
createPortal(child,container)child是任何可渲染的React元素,container是DOM元素,也就是需要挂载的地方。

// 1. 引入createPortal函数
import { createPortal } from 'react-dom'
export class App extends PureComponent {render () {return (<div><h1>AppH1</h1>{createPortal(<h2>App H2</h2>, document.querySelector('#root2'))}</div>)}
}
export default App

在这里插入图片描述

五、 Fragment组件

因为要求只能有一个根节点,所以每次写结构都要包裹一个div
当我们不想多一个div结构时,可以采用Fragment

import React, { Fragment, PureComponent } from 'react'
export class App extends PureComponent {render () {return (// <div>//   <h1>没吃早饭</h1>//   <h2>没吃午饭</h2>//   <h3>没吃晚饭</h3>// </div><Fragment><h1>没吃早饭</h1><h2>没吃午饭</h2><h3>没吃晚饭</h3></Fragment>)}
}

在这里插入图片描述
Fragment标签可以用是用<></>代替(语法糖)。需要注意,当需要在Fragment标签绑定key属性时,不能采用语法糖的形式。

     <><h1>没吃早饭</h1><h2>没吃午饭</h2><h3>没吃晚饭</h3></>

六、 严格模式StrictMode

StrictMode于Fragment一样,不会渲染到结构上面。主要用来显示程序中潜在的问题。严格模式的检查尽在开发模式下运行。

import React, { PureComponent, StrictMode } from 'react'
export class App extends PureComponent {render () {return (<div>{/* 对Home及其后代元素开启严格模式 */}<StrictMode><Home /></StrictMode><Profile /></div>)}
}

严格模式检查什么?

(1) 识别不安全的生命周期,检查是否使用过时的ref API

// Home.jsxUNSAFE_componentWillMount () {console.log("Home UNSAFE_componentWillMount")}render () {return (<div><h2 ref="title">Home Title</h2>{/* <h2>Home</h2> */}</div>)
}

严格模式下,会报错,提醒程序员,避免一些隐藏的bug。
在这里插入图片描述
如果Profile组件使用这两个过时的API及生命周期函数,仍可正常使用,不会报错误。

(2) 检查副作用
  严格模式检查下的组件的生命周期函数会被调用两次,以检查此处的逻辑代码当被多次调用是,是否会产生bug。在生产环境中是不会被调用两次的。
在这里插入图片描述
(3)检查是否使用其他废弃或过时(findDOMNode)的方法 ,给出警告

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/448839.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Qt-链接数据库可视化操作

1. 概述 Qt 能够支持对常见数据库的操作&#xff0c;例如&#xff1a; MySQL、Oracle、SqlServer 等等。 Qt SQL模块中的API分为三层&#xff1a;驱动层、SQL接口层、用户接口层。 驱动层为数据库和SQL接口层之间提供了底层的桥梁。 SQL接口层提供了对数据库的访问&#xff0…

Excel多级结构转成树结构形式

第一步&#xff1a;Excel文件的形式如下 第二步&#xff1a;转换成树结构可选形式 第三步&#xff1a;具体怎么实现&#xff1f; &#xff08;1&#xff09;、需要借助数据库中表来存储这些字段&#xff0c;一张表&#xff08;aa&#xff09;存Excel文件中的所有数据&#xff…

基于百度智能体开发爱情三十六计

基于百度智能体开发爱情三十六计 文章目录 基于百度智能体开发爱情三十六计1. 爱情三十六计智能体2. 三十六计开发创意3. 智能体开发实践3.1 基础配置3.2 进阶配置3.3 调优心得3.4可能会遇到的问题 4. 为什么选择文心智能体平台 1. 爱情三十六计智能体 爱情三十六计 是一款基于…

《计算机视觉》—— 基于PyCharm中的dlib库实现人脸关键点定位

文章目录 1. 安装必要的库2. 下载dlib的人脸检测器和关键点预测器模型3. 编写代码 人脸关键点定位是指通过计算机视觉技术&#xff0c;识别和定位人脸图像中的关键点&#xff0c;如眼睛、鼻子、嘴巴等特定位置。这些关键点的准确定位对于人脸识别、表情分析、姿态估计等应用具有…

分库分表方式介绍

分库分表方式 分库分表包括分库和分表两个部分&#xff0c;在生产中通常包括&#xff1a;垂直分库、水平分库、垂直分表、水平分表四种方式&#xff1b; 1、垂直分表 1.1 垂直分表定义 垂直分表就是在同一数据库内将一张表按照指定字段分成若干表&#xff0c;每张表仅存储其…

Unity中实现预制体自动巡逻与攻击敌人的完整实现指南

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

wireshark 解密浏览器https数据包

一、导出浏览器证书有两种方法 1、在浏览器快捷方式追加启动参数&#xff1a; --ssl-key-log-file"d:\log\2.log" C:\Users\Administrator\AppData\Local\Google\Chrome\Application\chrome.exe --ssl-key-log-file"d:\log\2.log" 2、环境变量中新建用…

整理—计算机网络

目录 网络OSI模型和TCP/IP模型 应用层有哪些协议 HTTP报文有哪些部分 HTTP常用的状态码 Http 502和 504 的区别 HTTP层请求的类型有哪些&#xff1f; GET和POST的使用场景&#xff0c;有哪些区别&#xff1f; HTTP的长连接 HTTP默认的端口是什么&#xff1f; HTTP1.1怎…

win10卸载软件后发现“应用和功能”中还残留着软件卸载项怎么办?

win10卸载软件后发现“应用和功能”中还残留着软件卸载项怎么办&#xff1f; 1、方法一&#xff1a;2、方法二&#xff1a;3、在 Windows 中卸载或删除应用和程序 1、方法一&#xff1a; 点击控制面板界面中的程序下方的删除程序。 2、方法二&#xff1a; 1.winR打开运行窗…

JAVA——IO流

目录 1.概述 字节流&#xff1a; 2.分类 3.输入文件数据 1.创建对象 2.写出数据 3.释放资源 4.读出文件数据 1.创建对象 2.读取数据 3.释放资源 5.字符集 a.ASCII b.GBK c.Unicode 6.乱码 7.编码、解码常见方法 a.编码方法 1.默认方式编码 2.指定方式编码 …

4.7 大数据应用场景

文章目录 今天&#xff0c;我非常荣幸能与大家分享一个充满潜力和变革的主题——大数据的应用场景。在这个信息爆炸的时代&#xff0c;大数据已经成为推动各行各业发展的重要驱动力。接下来&#xff0c;我将带领大家探索大数据在不同行业中的神奇应用。 首先&#xff0c;让我们…

Wed前端入门——HTML、CSS

Wed前端入门——HTML、CSS 一般的页面有HTML、CSS以及JavaScript组成 HTML定义了页面的结构和内容&#xff0c;包括文本、图像、链接等等CSS用于定义页面的布局和样式JS用于添加交互性和动态功能作用 一、HTML 基本格式&#xff1a; <!-- 文档类型为HTML --> <!D…

大语言模型实战教程首发:基于深度学习的大规模自然语言处理模型LLM详解 -Shelly

我是Shelly&#xff0c;一个专注于输出AI工具和科技前沿内容的AI应用教练&#xff0c;体验过300款以上的AI应用工具。关注科技及大模型领域对社会的影响10年。关注我一起驾驭AI工具&#xff0c;拥抱AI时代的到来。 大模型的热度&#xff0c;实在是很高&#xff0c;诺奖也颁给了…

读书笔记《有效需求分析》业务场景梳理

1. 关键思考链 2. 执行流程 3. 执行细则 1&#xff09;最重要的是从业务流程到业务场景的梳理。 2&#xff09;主、变、支、管流程&#xff08;待解读&#xff09; 3&#xff09;排序业务场景&#xff08;待分析&#xff09; 4&#xff09;各分支判断是独立的且需要系统支持&a…

Vite创建Vue3项目以及Vue3相关基础知识

1.创建Vue3项目 1.运行创建项目命令 # 使用 npm npm create vitelatest2、填写项目名称 3、选择前端框架 4、选择语法类型 5、按提示运行代码 不出意外的话&#xff0c;运行之后应该会出现 下边这个页面 6.延伸学习&#xff1a;对比webpack和vite&#xff08;这个是面试必考…

JVM(HotSpot):直接内存及其使用建议

文章目录 一、什么是直接内存&#xff1f;二、特点三、使用案例四、直接内存的管理 一、什么是直接内存&#xff1f; Direct Memory&#xff1a;系统内存 普通IO&#xff0c;运行原理图 磁盘到系统内存&#xff0c;系统内存到jvm内存。 NIO&#xff0c;运行原理图 划分了一块…

Webpack 完整指南

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;Webpack篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来webpack篇专栏内容:webpack介绍 目录 介绍 一、webpack 1.1、webpack是什么 1.2 webpack五个核心配置 1.…

FreeRTOS——中断管理

中断理论剖析 中断简介 中断是一种机制&#xff0c;用于处理高优先级的事件或故障。当一个中断事件发生时&#xff0c;单片机可以立即中断正在执行的程序&#xff0c;转而处理中断事件。这种机制可以提高系统的响应速度和实时性。 中断优先级分组设置 ARM Cortex-M使用了8位宽…

它思科技CTO聂玮奇:消除“AI幻觉”,搭建高可靠对话云平台丨数据猿专访

大数据产业创新服务媒体 ——聚焦数据 改变商业 近年来&#xff0c;大模型技术在全球范围内引起了广泛关注和应用热潮。 提到人工智能&#xff0c;很多人会想到它强大的运算能力和广泛的应用场景。如今&#xff0c;语言模型的发展如火如荼&#xff0c;但其中的“幻觉”问题却带…

川字结构布局/国字结构布局

1.串字结构布局 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><style&g…