Vue3前端框架实战手册——从入门到精通全攻略

文摘   职场   2024-07-14 17:49   广东  


序  言

摘要


第 1 章:Vue3介绍


第 2 章:setup选项



第 3 章:reactive和ref函数


第 4 章:computed计算属性

与Vue2保持一致,原始数据变化,依赖原始数据的变量也会自动发生变化。不同之处是Vue3通过引入computed函数创建计算属性,该函数接受一个getter函数作为参数,并返回一个只读的响应式引用。

第 5 章:watch监听器


第 6 章:生命周期函数


第 7 章:父子组件通信


第 8 章:模板引用


第 9 章:provide和inject


第 10 章:defineOpions


第 11 章:Pinia状态管理


第 12 章:Typescript



第 13 章:Vue3+Antdv


第 14 章:作者介绍

吴灿锦,吉林财经大学2019级本科生,曾作为长春鹰迅网络科技有限责任公司CEO,带领鹰迅公司团队在“互联网 +"和"挑战杯"等竞赛中斩获3个国家级,11个省部级奖项。

目前在上市公司从事Java开发工作已经超过两年了,参与了两个千万级用户的分布式系统的开发和维护工作,在做项目期间,对Mysql优化,分库分表,多线程,分布式锁,分布式事务,Redis缓存,RabbitMQ,xxl-job,ElasticSearch,SpringCloud微服务框架以及前端的Vue框架都有比较深入的研究,积累了丰富的实际经验和良好的职业履历。

欢迎访问我的个人网站:
www.yxclass.net


第 1 章

Vue3介绍


1.1、Vue3介绍


Vue3是Vue.js框架的最新版本,于2020年9月正式发布,其核心亮点有以下几点:

1. 增强的响应式系统:基于Proxy技术,提供更精准、高效的依赖追踪,优化数据响应性能。

2组合式API:引入Composition API,让逻辑复用与组件组织更加灵活,代码更易维护。

3性能优化:通过虚拟DOM算法改进,实现更快的渲染速度和更低的资源消耗。

4体积缩减:通过打包和运行时优化,Vue3相比前版本体积更小,加载更快。

5TypeScript深度集成:提升TypeScript支持,为大型项目提供更强的类型安全和开发效率。



1.2、选项式API和组合式API


1.2.1、Vue2选项式API


1.2.2、Vue3组合式API优势

1. 代码精简高效:利用setup函数及ref、reactive等API,使组件逻辑更加集中,减少了代码的分散和冗余,提高了代码的可读性和编写效率。
2. 维护集中便捷:将相关逻辑组织在同一setup函数中,便于开发者快速理解和维护组件状态与行为,同时支持自定义组合函数,提升代码复用性和可维护性。


1.3、create-vue搭建Vue3项目


1.3.1、使用create-vue创建项目

前置条件:已安装16.0或更高版本的Node.js。


1.3.2、项目结构说明


第 2 章

setup选项


2.1、setup选项的写法


在setup函数中写的数据和方法需要在末尾以对象的方式return,才能给模版使用。


2.2、setup执行时机


setup选项在beforeCreate钩子之前执行。


2.3、<script setup>语法糖


script标签添加 setup标记,不需要再写导出语句,默认会添加导出语句,使用const和var声明的响应式数据在<script setup>标签顶层被声明,无需return。


第 3 章

reactive和ref函数


3.1、reactive


3.1.1、reactive介绍

reactive 函数用于创建一个响应式的对象,它接受一个对象作为参数,并返回这个对象的响应式版本。这意味着,当你修改这个对象的属性时,任何依赖于这些属性的视图都会自动更新。

3.1.2、reactive代码示例


3.2、ref


3.2.1、ref介绍

ref 函数用于创建一个响应式的引用对象,它接受一个参数(可以是简单类型如数字、字符串,也可以是对象或数组),并返回一个响应式的对象,该对象包含一个名为 value 的属性,用于存储传入的值。

3.2.2、ref代码示例


3.3、reactive和ref对比


3.3.1、ref相同点

两者都用于创建响应式数据。


3.3.2、不同点

1. 数据类型:reactive 主要用于对象或数组等复杂类型,而 ref 可以用于任何类型的数据。

2. 访问方式:reactive 返回的对象直接通过属性名访问,而 ref 返回的对象需要通过 .value 属性访问其值。

3. 内部实现:对于对象或数组,ref 内部会调用 reactive 来处理。


3.3.3、应用场景

1. 对于简单类型数据(如数字、字符串),推荐使用 ref,因为它通过 .value访问统一访问。

2. 对于对象或数组等复杂类型数据,两者均可使用,但 reactive 更为直接,因为它不需要通过 .value 访问。

3. 在实际项目中,根据数据类型的不同和个人偏好选择使用 ref 或 reactive。重要的是保持代码的一致性和可维护性。

第 4 章

computed计算属性


4.1、computed介绍


计算属性(Computed Properties)在Vue 3的组合式API中,其基本思想与Vue 2保持一致,原始数据发生变化,依赖于原始数据的变量也会自动发生变化不同之处是Vue 3通过引入computed函数来创建计算属性,该函数接受一个getter函数作为参数,并返回一个只读的响应式引用。

4.2、computed代码示例



第 5 章

watch侦听器


5.1、watch介绍


在Vue 3的组合式API中,watch函数用于侦听响应式数据的变化,并在数据变化时执行回调函数。它提供了灵活性,允许你侦听单个或多个响应式引用,并且可以配置为立即执行回调函数或在深度监听对象时触发。

5.2、侦听单个数据



5.3、侦听多个数据



5.4、immediate


在这个例子中,即使 count 的值在创建时就是 0,并且没有立即发生变化,但由于设置了 immediate: true,watch 的回调函数还是会被执行一次,打印出当前的 count 值。这允许你在组件或页面加载时立即响应数据的初始状态。


5.5、deep


对于深度监听,我们通常监听对象或数组,并确保当对象内部的属性或数组内部的元素发生变化时,能够触发回调函数。


5.6、整体代码



第 6 章

生命周期函数


6.1、选项式API对比组合式API


在Vue3(特别是Vue 3的Composition API中)执行生命周期函数并传入回调,意味着你正在定义当组件的生命周期到达某个特定阶段时应该执行的代码块。生命周期函数是Vue组件中内置的特殊函数,它们在组件的不同阶段自动被调用,如创建、挂载、更新、卸载等。


6.2、组合式API


组合式API中主要生命周期钩子介绍:

1. setup:组件逻辑入口,替代data、methods等选项。
2. onBeforeMount:组件挂载前调用,用于设置准备工作。
3. onMounted:组件挂载后调用,可访问DOM。
4. onBeforeUpdate:组件更新前调用,数据变化前执行。
5. onUpdate:组件更新后调用,DOM更新完成。
6. onBeforeUnmount:组件卸载前调用,执行清理工作。
7. onUnmounted:组件卸载后调用,完成清理。

6.3、组合式API基本使用


6.3.1、语法格式

1. 导入生命周期函数。
2. 执行生命周期函数,传入回调。


6.3.2、应用示例


6.3.3、所有组合式API应用示例


第 7 章

父子组件通信


7.1、父传子


7.1.1、父传子基本思想

1. 父组件中给子组件绑定属性。
2. 子组件内部通过props选项接收数据。

7.1.2、父组件

父组件中给子组件绑定属性:在父组件的模板中,可以通过绑定属性的方式将数据传递给子组件。这是通过v-bind指令(或其简写:)来实现的。


7.1.3、子组件

子组件内部通过defineProps接收数据:在子组件的<script setup>部分,可以使用defineProps宏来声明这个组件所期望接收的props。这些props在组件的模板中可以直接使用。


7.2、子传父


7.2.1、子传父基本思想

子组件通过ref函数管理响应式数据,并使用事件(如$emit)将这些数据或变化作为参数传递给父组件,实现子到父的数据通信。

7.2.2、父组件

1. 使用ref函数生成一个响应式的数据。
2. import子组件对象。
3. 通过<template>部分绑定自定义事件监听器到子组件。
4. 定义一个方法来处理从子组件接收到的消息。


7.2.3、子组件

使用defineEmits宏定义可以触发的自定义事件。
定义一个方法来触发这些自定义事件,并传递参数。
在<template>部分添加一个按钮,当点击时调用这个方法。


7.2.3、注意事项

1. 事件定义与传递匹配:
(1)确保子组件使用defineEmits宏来定义所有要触发的事件。
(2)检查子组件中emit函数调用时的事件名与定义的一致,并确保传递的参数类型、数量与父组件监听该事件时期望接收的相匹配。

2. 事件监听与处理:
(1)在父组件的<template>中,使用@eventName="handlerFunction"的形式正确绑定事件监听器。
(2)确保父组件中存在与监听器绑定的方法(如handlerFunction),该方法能正确处理从子组件传递来的数据。

3. 响应式数据在组件中的使用:
(1)使用ref函数在父组件的<script setup>中创建响应式数据。
(2)若需在模板中展示或修改该数据,通过{{ someData.value }}来显示数据,或在需要修改时通过someData.value = newValue来更新数据。注意在模板中直接访问响应式引用时需要使用.value属性。


第 8 章

模板引用


8.1、模板引用


8.1.1、模板引用介绍

在Vue 3中,模板引用(Template Refs)是一种访问DOM元素或子组件实例的方式。它们允许你在Vue组件的模板中给元素或子组件添加ref属性,并在组件的<script setup>或<script>部分通过ref函数(来自Vue的reactive API)来引用这些元素或组件实例。

8.1.2、defineExpose介绍

在 Vue 3 中,<script setup> 语法糖为组件开发提供了更简洁的编写方式。然而,这种语法默认隐藏了组件内部的变量和方法,使其无法直接从组件外部访问。如果需要从父组件或外部访问子组件的某些属性或方法,可以通过 defineExpose 编译宏来显式地暴露它们。

8.2、使用ref获取DOM元素

textContent 是 DOM 元素的一个属性,它表示该元素及其后代的文本内容。


8.3、使用defineExpose暴露内部状态

在 Vue 3 的 <script setup> 语法中,为了保持组件的封装性和内部逻辑的隔离,组件的状态和方法默认是不对外暴露的。这意味着,除非特别声明,否则父组件或外部环境无法直接访问子组件内部的数据或方法。为了打破这种封装,让外部能够访问特定的内部成员,可以通过 defineExpose指定哪些属性(包括响应式状态、计算属性等)和方法可以暴露给组件的外部使用

8.3.1、子组件

在子组件中通过defineExpose将testMessage和changeMessage方法暴露给外部组件使用。


8.3.2、父组件

在父组件中,通过 <ChildComponent ref="childRef" /> 给子组件添加了一个 ref 属性,这样父组件就可以通过 this.$refs.childRef(在 <script setup> 中是 childRef.value)访问到子组件的实例了。


第 9 章

provide和inject


9.1、应用场景


provide 和 inject 是 Vue 3 中用于实现跨组件通信(尤其是跨层级组件)的一对 API。它们允许一个祖先组件(通常称为提供者)向其所有后代组件(无论层级多深)提供数据或方法,而不需要通过每一层组件显式地传递 props 或使用事件($emit)来通信。这在创建高阶组件库或需要在全局范围内共享数据时特别有用。

9.2、跨层传递普通数据


9.2.1、实现步骤

1. 顶层组件(提供者):使用 provide 函数提供数据。provide 函数通常在组件的 setup 函数中被调用,并且它接受两个参数:第一个是提供数据的名称(通常是一个唯一的标识符或字符串),第二个是要提供的数据值。

2. 底层组件(消费者):使用 inject 函数获取顶层组件提供的数据。inject 可以在任何组件的 setup 函数中使用,或者作为组合式 API 的一部分,来访问提供的数据。inject 函数接受一个参数,即提供数据的名称(与顶层组件中使用的名称相同)。

9.2.2、代码示例


9.3、跨层传递响应式数据


9.3.1、响应式数据介绍

当需要跨层传递响应式数据时,应确保提供的数据是响应式的。这通常意味着你需要使用 Vue 的响应式 API(如 ref 或 reactive)来创建数据。

9.3.2、代码示例


9.4、跨层传递方法


9.4.1、应用场景

顶层组件也可以向底层组件传递方法,这样底层组件就可以调用这些方法来修改顶层组件的状态或执行其他操作。

9.4.2、代码示例


第 10 章

defineOptions


10.1、背景说明


在 Vue 3 中,<script setup> 语法糖极大地提升了组件的编写效率和简洁性,它允许你将组件的响应式状态、计算属性、方法等直接写在 <script setup> 标签内部,而无需显式地定义一个 setup 函数。然而,这种语法也带来了一个限制:它不支持直接在 <script setup> 中声明一些传统的 Options API 选项,如 name、inheritAttrs 等,因为这些选项通常与组件的元信息或全局配置相关,而 <script setup> 更侧重于组件的响应式逻辑。

Vue3入了 defineProps 与 defineEmits 这两个宏。但这只解决了 props 与 emits 这两个属性。如果我们要定义组件的 name 或其他自定义的属性,还是得回到最原始的用法——再添加一个普通的 <script> 标签。这样就会存在两个 <script> 标签。

10.2、defineOptions


10.2.1、详细描述

为了在 <script setup> 中声明一些传统的 Options API 选项,Vue3.3引入了defineOptions(或类似概念的),defineOptions宏的主要作用是允许开发者在 <script setup> 内部以一种声明式的方式定义那些无法通过 defineProps、defineEmits 等宏直接处理的组件选项。这样,开发者就可以在不牺牲 <script setup> 带来的简洁性和便利性的同时,也能完整地定义组件的所有选项,而无需额外添加一个传统的 <script> 标签。

10.2.2、代码示例


第 11 章

Pinia状态管理


11.1、Pinia状态管理


11.1.1、Pinia介绍

Pinia 是 Vue.js 生态系统中的一个现代状态管理库,专为 Vue 3 设计,作为 Vuex 的下一代替代品,它带来了许多改进和简化的特性,使得状态管理在 Vue 应用中变得更加直观和高效。

11.1.2、Pinia优势

1. 简化API:Pinia通过去除Vuex中的mutations概念,大大简化了状态管理的API。开发者现在可以直接在actions中处理所有状态更新逻辑,无需区分何时使用mutations。这种设计使得状态更新更加直观和高效,同时也减少了代码冗余,提升了开发体验。

2. 符合Vue3风格:Pinia深度集成了Vue 3的组合式API,为开发者提供了一种全新的、与Vue 3设计哲学相契合的状态管理方式。通过利用Vue 3的响应式系统和组合式API,Pinia使得状态管理更加灵活和强大,同时也让Vue 3的开发者能够更快地适应并利用这一工具。

3. 独立模块:Pinia摒弃了Vuex中的modules概念,转而采用了一种更加简单和直观的模块化设计。在Pinia中,每个store都是一个独立的模块,可以轻松地通过导入和导出在组件或页面之间共享。这种设计不仅简化了store的创建和管理过程,还使得代码结构更加清晰和易于维护。

4. TypeScript友好:Pinia为TypeScript用户提供了强大的类型支持。通过与TypeScript的紧密集成,Pinia能够自动推断出store中状态的类型,并在开发过程中提供精确的类型提示和错误检查。这不仅减少了运行时错误的发生,还提高了代码的可读性和可维护性,使得TypeScript用户能够更加自信地管理Vue应用中的状态。

11.1.3、项目安装Pinia

npm install pinia或者yarn add pinia

11.2、Pinia基础使用


11.2.1、定义store

在 Pinia 中,可以通过 defineStore 函数来定义一个 store。


11.2.2、getter实现

在 Pinia 中,getters类似于 Vue 组件中的 computed 属性,当getter依赖的state发生变化时,getter会自动重新计算,用于基于 state 派生出新的状态。


11.2.3、Action异步实现

Pinia中的action用于处理异步或复杂逻辑,可修改state,可访问getters,类似于Vue组件中的methods。


11.3、Pinia持久化插件


11.3.1、Pinia持久化插件

使用 pinia-plugin-persistedstate 可以将 Pinia store 的状态持久化到本地存储(如 localStorage 或 sessionStorage)。


安装插件:

npm install pinia-plugin-persistedstate

11.3.2、使用插件


11.3.3、配置store


11.4、项目使用Pinia


11.4.1、state公共数据源


11.4.2、登录成功后存储用户信息


 登录成功后将用户信息存储到store中。


11.4.3、从Pinia中获取数据




11.4.4、发送请求从store中获取token


11.4.5、使用token进行身份验证

在<el-upload>组件中,通过:headers属性允许你向文件上传的请求中添加自定义的HTTP头部信息。这对于需要身份验证的场景尤为重要,比如上传文件到服务器时,服务器要求必须携带有效的token的请求,才会被服务器接受并处理文件上传。服务器验证token,确保上传请求是由合法用户发起的,增强系统的安全性。防止非法上传。



第 12 章

TypeScript


12.1、类型问题


12.1.1、动态类型的问题

在 JavaScript 中,由于其动态类型的特性,函数的参数类型在编写时是不确定的。这虽然提供了极大的灵活性,但也带来了潜在的风险,比如类型错误可能导致程序崩溃。

动态类型意味着在运行时才能确定变量的具体类型,这增加了调试的复杂性和出错的可能性。


12.1.2、静态类型的优势

TypeScript 作为一种静态类型语言的扩展,为 JavaScript 提供了类型系统。在 TypeScript 中,你可以在代码运行之前就确定变量的类型,这有助于减少运行时错误,并提供更好的代码自动完成和重构支持。

12.2、TypeScript应用示例


12.2.1、安装 TypeScript 编译器

npm install -g typescript


12.2.2、TypeScript代码示例


当你运行 TypeScript 编译器(tsc xxx.ts)时,它会将 TypeScript 代码编译成纯 JavaScript 代码,同时移除所有的类型注解和接口定义(这个过程称为类型擦除)。因此,生成的 JavaScript 代码与原始的 TypeScript 代码在功能上是一致的,但没有了类型检查。


12.2.3、总结

TypeScript 通过在编译时实施类型检查,显著提高了 JavaScript 代码的健壮性和可维护性。尽管最终生成的 JavaScript 代码不包含类型信息,但开发过程中的类型检查可以大大减少运行时错误,并提高开发效率。

12.3、TypeScript类型




12.4、标注类型


在 TypeScript 中,标注(或称为注解)是提供类型信息的一种方式,它帮助 TypeScript 编译器在编译时进行类型检查。以下是对不同位置标注的详细解释和优化。

12.4.1、标注变量


虽然 TypeScript 通常能够根据变量的初始值推断出变量的类型,但显式标注变量类型可以提供更清晰的代码意图和额外的类型安全。



12.4.2、标注参数


在函数定义中,参数的类型标注是常见的做法,尤其是当参数的用途或类型不那么直观时。



12.4.3、标注返回值


函数返回值的类型标注也是重要的,尤其是在函数较为复杂,其返回类型不易从实现中直接推断出来时。


12.4.4、type和interface


type 和 interface 在 TypeScript 中用于定义复杂类型。type 通常用于更简单的别名,而 interface 更适合定义对象的形状,包括可选属性、只读属性等。



12.4.5、可选性


在 interface 或 type 中,你可以使用 ? 标记某个属性为可选的。



12.4.6、鸭子类型


TypeScript 支持结构子类型化(也称为鸭子类型),这意味着只要对象的结构兼容,就可以将其用作预期的类型,而无需显式声明类型。



12.4.7、方法类型


在接口中定义方法时,你可以指定方法的参数和返回类型。



12.4.8、字面量类型


字面量类型提供了一种方式来限制变量的值只能是特定的几个值之一。


12.5、TypeScript的意义


12.5.1、更好的理解框架


现在越来越多的前端框架采用 typescript,如果懂 typescript 语法,可以更好地阅读框架代码


以Map的使用为例,TypeScript通过泛型为Map提供了类型安全,使得在开发过程中能够清晰地知道Map中存储的键值对类型,减少了类型错误的发生。



12.5.2、更好的类型提示和错误检查


TypeScript的一个核心优势是提供了强大的类型系统和静态类型检查。这意味着在编写代码时,编辑器(如VS Code, WebStorm等)能够基于TypeScript的类型定义给出准确的提示和错误检查,从而帮助开发者避免常见的错误。

以下是一个关于从服务器获取JSON数据并使用TypeScript进行类型定义的例子:


上面的代码示例中使用了as User进行类型断言,但这只是告诉TypeScript编译器:“我知道这个值是什么类型,请相信我。”它并不会在运行时进行类型检查。在实际应用中,如果JSON结构可能变化或来自不可信的源,建议使用更安全的方法来处理JSON到TypeScript的转换,比如使用专门的序列化库来确保类型安全。


12.6、类


在TypeScript中,类(Class)是一种强大的面向对象编程特性,尽管其背后的实现机制在JavaScript中是基于原型的。TypeScript通过提供类型注解和接口等特性,增强了JavaScript中的类语法,使其更加安全和易于维护。然而,需要明确的是,TypeScript中的类语法并不是核心,更重要的是理解接口(Interface)等概念在面向对象编程中的作用。


12.6.1、基本语法


TypeScript中的类定义类似于传统面向对象语言中的类定义,但添加了类型注解。



12.6.2、只读属性


TypeScript通过readonly关键字提供了一种方式来声明类的只读属性,即这些属性在创建实例后不能被重新赋值。



12.6.3、方法


类中可以包含方法,即定义在类上的函数。方法可以访问类的属性,并且可以通过类的实例来调用。



12.6.4、set和get


在TypeScript中,get 和 set 访问器允许你对类的属性进行更细粒度的控制。你可以通过它们来拦截对属性的访问和修改,执行一些额外的逻辑。



12.6.5、类与接口


接口在TypeScript中用于定义一个类的结构,确保类具有某些特定的属性和方法。类通过implements关键字来实现接口。



12.6.6、接口与继承


在TypeScript中,类可以继承其他类,并且可以实现一个或多个接口。这允许你创建具有层次结构和类型约束的复杂对象模型。



12.6.7、方法重写


在TypeScript中,子类可以重写继承自父类的方法。这允许子类提供特定于子类的行为,同时仍然保留对父类方法的访问(通过super关键字)。



第 13 章

Vue3+Antdv


13.1、创建项目


13.1.1、创建项目


my-vue-app 是项目名称,可以根据需要修改。--template vue 参数指定了项目模板为 Vue 3。


npm init vite@latest my-vue-app -- --template vue

13.1.2、安装依赖


cd my-vue-appnpm install


13.1.3、运行项目


npm run dev

13.2、项目结构



13.3、配置代理



13.4、axios


13.4.1、项目引入axios

步骤1:在项目的根目录下打开终端,然后输入以下命令来安装Axios。


npm install axios --save//或者yarn add axios

步骤2:在request.ts中把axios依赖引进来。


13.4.2、环境变量管理

在 Vue 3 和 Vite 构建的项目中,管理不同环境下的后端服务器地址是一个常见的需求。Vite 提供了灵活的环境变量支持,允许我们根据开发环境(development)和生产环境(production)来设置不同的配置。


开发环境下,联调的后端服务器地址是 http://localhost:8080,

上线改为生产环境后,后端服务器地址为 http://yxclass.net。



配置后端环境:



13.4.3、拦截器


13.5、Antdv


13.5.1、项目引入Antdv

npm install ant-design-vue


13.5.2、启用Antdv功能


13.6、vue-router


Vue前端框架实战手册——从入门到精通全攻略

13.7、项目引入pinia


npm install pinia


13.8、表格分页


13.8.1、表格结构


表头结构:


13.8.2、表格数据展示



第 14 章

作者介绍


吴灿锦,泰伯一百零一世孙,明朝开国名将安陆侯吴复的后代,吉林财经大学2019级本科生;


第九届中国国际“互联网+”创新创业大赛吉林省赛区金奖项目总负责人;


第十三届“挑战杯”中国大学生创业计划大赛吉林省赛区特等奖,国家级铜奖项目总负责人;


2022年荣获吉林财经大学创业实践国家级立项第一名项目总负责人。


· 往期回顾 ·


“互联网+”金奖与“挑战杯”特等奖——青春的舞台,美好的回忆
《刻意练习》深度解读——如何通过刻意练习让你变成一个卓越的人
ElasticSearch分布式搜索引擎实战手册——从入门到精通全攻略
Vue前端框架实战手册——从入门到精通全攻略
大数据高并发系统架构实战方案
SpringCloud微服务架构实战手册——从入门到精通全攻略
优秀毕业设计示例——基于SpringCloud Alibaba微服务在线教育系统的设计与实现的路演答辩
RabbitMQ异步通信全攻略——API操作与性能调优实战
Redis核心API速览与实战应用手册
JDK核心API速查手册与实用指南
Java开发手册阅读心得——黄山版
SpringBoot项目常用注解的积累与代码的优化实践
Spring Framework——掌握核心注解,优化你的应用程序
工作中常用的Linux命令——以阿里云ECS服务器为例
Mysql数据库系统学习笔记


远方的音讯
梧桐长成凤凰至,人伴贤良品行高!
 最新文章