Web前端最全菜鸟教程react笔记【20240329】,面试哪些
本人分享一下这次字节跳动、美团、头条等大厂的面试真题涉及到的知识点,以及我个人的学习方法、学习路线等,当然也整理了一些学习文档资料出来是给大家的。知识点涉及比较全面,包括但不限于前端基础,HTML,CSS,JavaScript,Vue,ES6,HTTP,浏览器,算法等等开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】// 又对啦!key应该在数组的上下文中被指定ret
文末
从转行到现在,差不多两年的时间,虽不能和大佬相比,但也是学了很多东西。我个人在学习的过程中,习惯简单做做笔记,方便自己复习的时候能够快速理解,现在将自己的笔记分享出来,和大家共同学习。
个人将这段时间所学的知识,分为三个阶段:
第一阶段:HTML&CSS&JavaScript基础

第二阶段:移动端开发技术

第三阶段:前端常用框架

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
-
推荐学习方式:针对某个知识点,可以先简单过一下我的笔记,如果理解,那是最好,可以帮助快速解决问题;
-
大厂的面试难在,针对一个基础知识点,比如JS的事件循环机制,不会上来就问概念,而是换个角度,从题目入手,看你是否真正掌握。所以对于概念的理解真的很重要。
除了函数外我们还可以创建一个 React.Component 的 ES6 类,该类封装了要展示的元素,需要注意的是在 render() 方法中,需要使用 this.props 替换 props
class Clock extends React.Component {
render() {
return (
Hello, world!
现在是 {this.props.date.toLocaleTimeString()}.
);
}
}
function tick() {
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById(‘example’)
);
}
setInterval(tick, 1000);
React 只会更新必要的部分
值得注意的是 React DOM 首先会比较元素内容先后的不同,而在渲染过程中只会更新改变了的部分。
=====================================================================
React 使用 JSX 来替代常规的 JavaScript。
JSX 是一个看起来很像 XML 的 JavaScript 语法扩展。
我们不需要一定使用 JSX,但它有以下优点:
-
JSX 执行更快,因为它在编译为 JavaScript 代码后进行了优化。
-
它是类型安全的,在编译过程中就能发现错误。
-
使用 JSX 编写模板更加简单快速。
元素是构成 React 应用的最小单位,JSX 就是用来声明 React 当中的元素。
与浏览器的 DOM 元素不同,React 当中的元素事实上是普通的对象,React DOM 可以确保 浏览器 DOM 的数据内容与 React 元素保持一致。
要将 React 元素渲染到根 DOM 节点中,我们通过把它们都传递给 ReactDOM.render() 的方法来将其渲染到页面上:
var myDivElement =
ReactDOM.render(myDivElement, document.getElementById(‘example’));
注意:
由于 JSX 就是 JavaScript,一些标识符像 class 和 for 不建议作为 XML 属性名。作为替代,React DOM 使用 className 和 htmlFor 来做对应的属性。
JSX 看起来类似 HTML ,我们可以在以上代码中嵌套多个 HTML 标签,需要使用一个 div 元素包裹它,实例中的 p 元素添加了自定义属性 data-myattribute,添加自定义属性需要使用 data- 前缀。
你的 React JSX 代码可以放在一个独立文件上,例如我们创建一个 helloworld_react.js 文件,代码如下:
ReactDOM.render(
Hello, world!
, document.getElementById(‘example’) );然后在 HTML 文件中引入该 JS 文件:
在 JSX 中不能使用 if else 语句,但可以使用 conditional (三元运算) 表达式来替代。以下实例中如果变量 i 等于 1 浏览器将输出 true, 如果修改 i 的值,则会输出 false.
ReactDOM.render(
{i == 1 ? 'True!' : 'False'}
,
document.getElementById(‘example’)
);
React 推荐使用内联样式。我们可以使用 camelCase 语法来设置内联样式. React 会在指定元素数字后自动添加 px 。以下实例演示了为 h1 元素添加 myStyle 内联样式:
var myStyle = {
fontSize: 100,
color: ‘#FF0000’
};
ReactDOM.render(
菜鸟教程
,document.getElementById(‘example’)
);
注释需要写在花括号中
{/注释…/}
JSX 允许在模板中插入数组,数组会自动展开所有成员对象
var arr = [
菜鸟教程
,学的不仅是技术,更是梦想!
,];
ReactDOM.render(
document.getElementById(‘example’)
);
====================================================================
将讨论如何使用组件使得我们的应用更容易来管理
接下来我们封装一个输出 “Hello World!” 的组件,组件名为 HelloMessage
function HelloMessage(props) {
return
Hello World!
;}
const element = ;
ReactDOM.render(
element,
document.getElementById(‘example’)
);
1、我们可以使用函数定义了一个组件
function HelloMessage(props) {
return
Hello World!
;}
你也可以使用 ES6 class 来定义一个组件,把return语句封在render(){}里面
class Welcome extends React.Component {
render() {
return
Hello World!
;}
}
2、const element = <HelloMessage />为用户自定义的组件。
注意,原生 HTML 元素名以小写字母开头,而自定义的 React 类名以大写字母开头,比如 HelloMessage 不能写成 helloMessage。除此之外还需要注意组件类只能包含一个顶层标签,否则也会报错。
如果我们需要向组件传递参数,可以使用 this.props 对象
function HelloMessage(props) {
return
Hello {props.name}!
;}
const element = ;
ReactDOM.render(
element,
document.getElementById(‘example’)
);
以上实例中 name 属性通过 props.name 来获取
在添加属性时, class 属性需要写成 className ,for 属性需要写成 htmlFor ,这是因为 class 和 for 是 JavaScript 的保留字。
把不同的React.Component封装在App里面
多个属性的传入注意不用逗号或分号隔开而是空格符隔开:
var myStyle = {color:‘red’,textAlign:‘center’}
class Name extends React.Component {
render() {
return
网站名称:{this.props.name}
;}
}
class Url extends React.Component {
render() {
return
网站地址:{this.props.url}
;}
}
class Nickname extends React.Component {
render() {
return
网站地址:{this.props.nickname}
;}
}
class App extends React.Component {
render(){
return (
{/传入"菜鸟教程"/}
);
}
}
/*function App(props) {
-
return (
-
<div> -
<Name name={props.name}/> -
<Url url={props.url}/> -
<Nickname nickname={props.nickname}/> -
</div> -
);
}*/
ReactDOM.render(
<App name={“菜鸟教程”} url={“http://www.runoob.com”} nickname={“Runoob”}/>,
document.getElementById(‘example’)
);
===========================================================================
React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。
React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。
以下实例创建一个名称扩展为 React.Component 的 ES6 类,在 render() 方法中使用 this.state 来修改当前的时间。
添加一个类构造函数来初始化状态 this.state,类组件应始终使用 props 调用基础构造函数。
在具有许多组件的应用程序中,在销毁时释放组件所占用的资源非常重要。
每当 Clock 组件第一次加载到 DOM 中的时候,我们都想生成定时器,这在 React 中被称为挂载。
同样,每当 Clock 生成的这个 DOM 被移除的时候,我们也会想要清除定时器,这在 React 中被称为卸载。
我们可以在组件类上声明特殊的方法,当组件挂载或卸载时,来运行一些代码
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {//挂载
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {//卸载
clearInterval(this.timerID);
}
tick() {//实际的执行器
this.setState({
date: new Date()
},
()=>{console.log(this.state)}// this.setState的执行回调
);
}
render() {
return (
Hello, world!
现在是 {this.state.date.toLocaleTimeString()}.
);
}
}
ReactDOM.render(
,
document.getElementById(‘example’)
);
实例解析:
-
componentDidMount() 与 componentWillUnmount() 方法被称作生命周期钩子。
-
在组件输出到 DOM 后会执行 componentDidMount() 钩子,我们就可以在这个钩子上设置一个定时器。
-
this.timerID 为定时器的 ID,我们可以在 componentWillUnmount() 钩子中卸载定时器。
-
如果需要修改this.state中的数据 必须调用this.setstate这个方法.
-
使用对this.state赋值并没有什么作用,官方提醒,应该把this.state当成不可变变量。
而使用this.setState方法,会触发异步修改状态,状态改变的同时,会重新执行一次willUpdate,render等流程。
代码执行顺序:
-
当
<Clock />被传递给ReactDOM.render()时,React 调用Clock组件的构造函数。 由于Clock需要显示当前时间,所以使用包含当前时间的对象来初始化this.state。 我们稍后会更新此状态。 -
React 然后调用
Clock组件的render()方法。这是 React 了解屏幕上应该显示什么内容,然后 React 更新 DOM 以匹配Clock的渲染输出。 -
当
Clock的输出插入到 DOM 中时,React 调用componentDidMount()生命周期钩子。 在其中,Clock组件要求浏览器设置一个定时器,每秒钟调用一次tick()。 -
浏览器每秒钟调用
tick()方法。 在其中,Clock组件通过使用包含当前时间的对象调用setState()来调度UI更新。 通过调用setState(),React 知道状态已经改变,并再次调用render()方法来确定屏幕上应当显示什么。 这一次,render()方法中的this.state.date将不同,所以渲染输出将包含更新的时间,并相应地更新 DOM。 -
一旦
Clock组件被从 DOM 中移除,React 会调用componentWillUnmount()这个钩子函数,定时器也就会被清除。
父组件或子组件都不能知道某个组件是有状态还是无状态,并且它们不应该关心某组件是被定义为一个函数还是一个类。
这就是为什么状态通常被称为局部或封装。 除了拥有并设置它的组件外,其它组件不可访问。
以下实例中 FormattedDate 组件将在其属性中接收到 date 值,并且不知道它是来自 Clock 状态、还是来自 Clock 的属性、亦或手工输入
function FormattedDate(props) {
return
现在是 {props.date.toLocaleTimeString()}.
;}
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
Hello, world!
);
}
}
ReactDOM.render(
,
document.getElementById(‘example’)
);
这通常被称为自顶向下或单向数据流。 任何状态始终由某些特定组件所有,并且从该状态导出的任何数据或 UI 只能影响树中下方的组件。
为了表明所有组件都是真正隔离的,我们可以创建一个 App 组件,它渲染三个Clock
function FormattedDate(props) {
return
现在是 {props.date.toLocaleTimeString()}.
;}
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
Hello, world!
);
}
}
function App() {
return (
);
}
ReactDOM.render(, document.getElementById(‘example’));
也可以通过数组方式
let App=[ ,
,
];
ReactDOM.render(
=======================================================================
state 和 props 主要的区别在于 props 是不可变的,而 state 可以根据与用户交互来改变。这就是为什么有些容器组件需要定义 state 来更新和修改数据。 而子组件只能通过 props 来传递数据。
className.defaultProps指定了默认的属性和方法

以下实例演示了如何在应用中组合使用 state 和 props 。我们可以在父组件中设置 state, 并通过在子组件上使用 props 将其传递到子组件上。在 render 函数中, 我们设置 name 和 site 来获取父组件传递过来的数据。
class WebSite extends React.Component {
constructor() {
super();
this.state = {
name: “菜鸟教程”,
site: “https://www.runoob.com”
}
}
render() {
return (
);
}
}
class Name extends React.Component {
render() {
return (
{this.props.name}
);
}
}
class Link extends React.Component {
render() {
return (
{this.props.site}
);
}
}
ReactDOM.render(
,
document.getElementById(‘example’)
);
React.PropTypes 在 React v15.5 版本后已经移到了 prop-types 库。
Props 验证使用 propTypes,它可以保证我们的应用组件被正确使用,React.PropTypes 提供很多验证器 (validator) 来验证传入数据是否有效。当向 props 传入无效数据时,JavaScript 控制台会抛出警告。
以下实例创建一个 Mytitle 组件,属性 title 是必须的且是字符串,不然就是控制台报错
(菜鸟里面写的是会自动转换但是我没有试验出来)

如果我换成数字表达式,控制台报错但是props值仍然会传递
更多验证器(dictionary)
MyComponent.propTypes = {
// 可以声明 prop 为指定的 JS 基本数据类型,默认情况,这些数据是可选的
optionalArray: React.PropTypes.array,//数组
optionalBool: React.PropTypes.bool,//布尔
optionalFunc: React.PropTypes.func,//函数
optionalNumber: React.PropTypes.number,//数字
optionalObject: React.PropTypes.object,//对象
optionalString: React.PropTypes.string,//字符串
// 可以被渲染的对象 numbers, strings, elements 或 array
optionalNode: React.PropTypes.node,
// React 元素
optionalElement: React.PropTypes.element,
// 用 JS 的 instanceof 操作符声明 prop 为类的实例。
optionalMessage: React.PropTypes.instanceOf(Message),
// 用 enum 来限制 prop 只接受指定的值。
optionalEnum: React.PropTypes.oneOf([‘News’, ‘Photos’]),
// 可以是多个对象类型中的一个
optionalUnion: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.number,
React.PropTypes.instanceOf(Message)
]),
// 指定类型组成的数组
optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),
// 指定类型的属性构成的对象
optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),
// 特定 shape 参数的对象
optionalObjectWithShape: React.PropTypes.shape({
color: React.PropTypes.string,
fontSize: React.PropTypes.number
}),
// 任意类型加上 isRequired 来使 prop 不可空。
requiredFunc: React.PropTypes.func.isRequired,
// 不可空的任意类型
requiredAny: React.PropTypes.any.isRequired,
// 自定义验证器。如果验证失败需要返回一个 Error 对象。不要直接使用 console.warn 或抛异常,因为这样 oneOfType 会失效。
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error(‘Validation failed!’);
}
}
}
}
======================================================================
React 元素的事件处理和 DOM 元素类似。但是有一点语法上的不同:
-
React 事件绑定属性的命名采用驼峰式写法,而不是小写。
-
如果采用 JSX 的语法你需要传入一个函数作为事件处理函数,而不是一个字符串(DOM 元素的写法)
HTML 通常写法是:
激活按钮
React 中写法为:
激活按钮
在 React 中另一个不同是你不能使用返回 false 的方式阻止默认行为, 你必须明确的使用 preventDefault。
例如,通常我们在 HTML 中阻止链接默认打开一个新页面,可以这样写:
点我
在 React 的写法为:
function ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log(‘链接被点击’);
}
return (
点我
);
}
实例中 e 是一个合成事件。
使用 React 的时候通常你不需要使用 addEventListener 为一个已创建的 DOM 元素添加监听器。你仅仅需要在这个元素初始渲染的时候提供一个监听器。
当你使用 ES6 class 语法来定义一个组件的时候,事件处理器会成为类的一个方法。
例如,下面的 Toggle 组件渲染一个让用户切换开关状态的按钮:

两个容器不相互影响
你必须谨慎对待 JSX 回调函数中的 this,类的方法默认是不会绑定 this 的。如果你忘记绑定 this.handleClick 并把它传入 onClick, 当你调用这个函数的时候 this 的值会是 undefined。
这并不是 React 的特殊行为;它是函数如何在 JavaScript 中运行的一部分。通常情况下,如果你没有在方法后面添加 () ,例如onClick={this.handleClick},你应该为这个方法绑定 this。
如果使用 bind 让你很烦,这里有两种方式可以解决。如果你正在使用实验性的属性初始化器语法,你可以使用属性初始化器来正确的绑定回调函数:
//如果不想用bind可以使用箭头函数,
// handleClick = () => {
// console.log(‘this is:’, this);
// this.setState(prevState => ({
// isToggleOn: !prevState.isToggleOn
// }));
// }
//或者button处绑定<button onClick={(e) => this.handleClick(e)}>
每次 LoggingButton 渲染的时候都会创建一个不同的回调函数,这些组件可能会进行额外的重新渲染。通常建议在构造函数中绑定或使用属性初始化器语法来避免这类性能问题。(建议:bind或者箭头函数)
通常我们会为事件处理程序传递额外的参数。例如,若是 id 是你要删除那一行的 id,以下两种方式都可以向事件处理程序传递参数:
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row
<button onClick={this.deleteRow.bind(this, id)}>Delete Row
上述两种方式是等价的。
参数 e 作为 React 事件对象将会被作为第二个参数进行传递。通过箭头函数的方式,事件对象必须显式的进行传递,但是通过 bind 的方式,事件对象以及更多的参数将会被隐式的进行传递。
class Popper extends React.Component{
constructor(){
super();
this.state = {name:‘Hello world!’};
}
preventPop(name, e){ //事件对象e要放在最后
//name=this.state.name
//e被隐藏了是事件对象
e.preventDefault();
alert(name);
}
render(){
return (
hello
{/* 通过 bind() 方法传递参数。 */}
);
}
}
======================================================================
在 React 中,你可以创建不同的组件来封装各种你需要的行为。然后还可以根据应用的状态变化只渲染其中的一部分。
React 中的条件渲染和 JavaScript 中的一致,使用 JavaScript 操作符 if 或条件运算符来创建表示当前状态的元素,然后让 React 根据它们来更新 UI。
你可以使用变量来储存元素。它可以帮助你有条件的渲染组件的一部分,而输出的其他部分不会更改。
在下面的例子中,我们将要创建一个名为 LoginControl 的有状态的组件。
它会根据当前的状态来渲染 <LogoutButton />或 <LoginButton />,它也将渲染前面例子中的 <Greeting />
为方便观察,我将原文的bind都改成es6的箭头函数
你可以通过用花括号包裹代码在 JSX 中嵌入任何表达式 ,也包括 JavaScript 的逻辑与 &&,它可以方便地条件渲染一个元素。
function Mailbox(props) {
const unreadMessages = props.unreadMessages;
return (
Hello!
{unreadMessages.length > 0 &&
您有 {unreadMessages.length} 条未读信息。
}
);
}
const messages = [‘React’, ‘Re: React’, ‘Re:Re: React’];
ReactDOM.render(
,
document.getElementById(‘example’)
);
条件渲染的另一种方法是使用 JavaScript 的条件运算符:
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
{isLoggedIn ? (
) : (
)}
);
}
在极少数情况下,你可能希望隐藏组件,即使它被其他组件渲染。让 render 方法返回 null 而不是它的渲染结果即可实现。
比如:
function WarningBanner(props) {
if (!props.warn) {
return null;
}
return (
警告!
);
}
但是组件的 render 方法返回 null 并不会影响该组件生命周期方法的回调。

===========================================================================
我们可以使用 JavaScript 的 map() 方法来创建列表
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((numbers) =>
- {numbers}
-
);
ReactDOM.render(
- {listItems}
document.getElementById(‘example’)
);
组件接收数组参数,每个列表元素分配一个 key,不然会出现警告 a key should be provided for list items,意思就是需要包含 key
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
-
{number}
);
return (
- {listItems}
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
,
document.getElementById(‘example’)
);
Keys 可以在 DOM 中的某些元素被增加或删除的时候帮助 React 识别哪些元素发生了变化。因此你应当给数组中的每一个元素赋予一个确定的标识。
当元素没有确定的 id 时,你可以使用他的序列号索引 index 作为 key:
const todoItems = todos.map((todo, index) =>
// 只有在没有确定的 id 时使用
-
{todo.text}
);
一个元素的 key 最好是这个元素在列表中拥有的一个独一无二的字符串。通常,我们使用来自数据的 id 作为元素的 key:
const todoItems = todos.map((todo) =>
-
{todo.text}
);
如果列表可以重新排序,我们不建议使用索引来进行排序,因为这会导致渲染变得很慢。
元素的 key 只有在它和它的兄弟节点对比时才有意义。
比方说,如果你提取出一个 ListItem 组件,你应该把 key 保存在数组中的这个 **** 元素上,而不是放在 ListItem 组件中的
< ListItem />元素上。
function ListItem(props) {
// 对啦!这里不需要指定key:
return
- {props.value}
- ;
}
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
// 又对啦!key应该在数组的上下文中被指定
<ListItem key={number.toString()}
value={number} />
);
return (
{listItems}
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
,
document.getElementById(‘example’)
);
数组元素中使用的 key 在其兄弟之间应该是独一无二的。然而,它们不需要是全局唯一的。当我们生成两个不同的数组时,我们可以使用相同的键。
key 会作为给 React 的提示,但不会传递给你的组件。如果您的组件中需要使用和 key 相同的值,请将其作为属性传递:
const content = posts.map((post) =>
<Post
key={post.id}
id={post.id}
title={post.title} />
);
Post 组件可以读出 props.id,但是不能读出 props.key。
在上面的例子中,我们声明了一个单独的 listItems 变量并将其包含在 JSX 中
React 实例 ========================================================================
在本章节中我们将讨论 React 组件 API。我们将讲解以下7个方法:
-
设置状态:setState
-
替换状态:replaceState(废)
最后
本人分享一下这次字节跳动、美团、头条等大厂的面试真题涉及到的知识点,以及我个人的学习方法、学习路线等,当然也整理了一些学习文档资料出来是给大家的。知识点涉及比较全面,包括但不限于前端基础,HTML,CSS,JavaScript,Vue,ES6,HTTP,浏览器,算法等等

前端视频资料:

unction NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
// 又对啦!key应该在数组的上下文中被指定
<ListItem key={number.toString()}
value={number} />
);
return (
{listItems}
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
,
document.getElementById(‘example’)
);
数组元素中使用的 key 在其兄弟之间应该是独一无二的。然而,它们不需要是全局唯一的。当我们生成两个不同的数组时,我们可以使用相同的键。
key 会作为给 React 的提示,但不会传递给你的组件。如果您的组件中需要使用和 key 相同的值,请将其作为属性传递:
const content = posts.map((post) =>
<Post
key={post.id}
id={post.id}
title={post.title} />
);
Post 组件可以读出 props.id,但是不能读出 props.key。
在上面的例子中,我们声明了一个单独的 listItems 变量并将其包含在 JSX 中
React 实例 ========================================================================
在本章节中我们将讨论 React 组件 API。我们将讲解以下7个方法:
-
设置状态:setState
-
替换状态:replaceState(废)
最后
本人分享一下这次字节跳动、美团、头条等大厂的面试真题涉及到的知识点,以及我个人的学习方法、学习路线等,当然也整理了一些学习文档资料出来是给大家的。知识点涉及比较全面,包括但不限于前端基础,HTML,CSS,JavaScript,Vue,ES6,HTTP,浏览器,算法等等
[外链图片转存中…(img-UP39BBf6-1715896189092)]
前端视频资料:
[外链图片转存中…(img-dsCCoaPU-1715896189092)] -
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐



所有评论(0)