前端分页与瀑布流最佳实践笔记 - React Antd 版

前端分页与瀑布流最佳实践笔记 - React Antd 版

1. 分页与瀑布流对比

分页(Pagination)瀑布流(Infinite Scroll)
展示方式按页分批加载,有明确页码控件滚动到底部时自动加载更多内容,无明显分页
用户控制用户可主动翻页和跳转到任意页用户只能通过滚动浏览,无法直接跳转
数据加载时机用户点击翻页按钮时加载滚动接近底部时自动加载
适用场景数据量大且需精准定位(电商、后台管理系统)信息流浏览(社交媒体、图片墙)
体验特点更可控、易跳转,适合严肃场景更流畅、自然,适合娱乐、轻松浏览
技术实现通过currentpageSize参数请求监听滚动事件,触发加载

核心区别:分页更适合管理和精准查找,瀑布流更适合浏览体验和沉浸式内容。

2. 分页实现 - React Antd

基本实现

import { Table, Pagination } from 'antd';
import { useState, useEffect } from 'react';
import axios from 'axios';function PaginatedTable() {const [data, setData] = useState([]);const [loading, setLoading] = useState(false);const [pagination, setPagination] = useState({current: 1,pageSize: 10,total: 0});const fetchData = async (params = {}) => {setLoading(true);try {const response = await axios.get('/api/items', {params: {page: params.current || pagination.current,pageSize: params.pageSize || pagination.pageSize}});setData(response.data.items);setPagination({...pagination,current: params.current || pagination.current,total: response.data.total});} catch (error) {console.error('Error fetching data:', error);} finally {setLoading(false);}};useEffect(() => {fetchData();}, []);const handleTableChange = (paginate) => {fetchData({current: paginate.current,pageSize: paginate.pageSize});};const columns = [// 定义列{ title: 'Name', dataIndex: 'name', key: 'name' },{ title: 'Age', dataIndex: 'age', key: 'age' },// ...其他列];return (<Tablecolumns={columns}dataSource={data}pagination={pagination}loading={loading}onChange={handleTableChange}rowKey="id"/>);
}

分页优化技巧

  1. 缓存已加载的页面数据
const [cachedData, setCachedData] = useState({});const fetchData = async (params = {}) => {const current = params.current || pagination.current;const pageSize = params.pageSize || pagination.pageSize;const cacheKey = `${current}-${pageSize}`;// 检查缓存中是否已有此页数据if (cachedData[cacheKey]) {setData(cachedData[cacheKey]);return;}setLoading(true);try {const response = await axios.get('/api/items', {params: { page: current, pageSize }});// 更新数据和缓存setData(response.data.items);setCachedData({...cachedData,[cacheKey]: response.data.items});setPagination({...pagination,current,total: response.data.total});} catch (error) {console.error('Error:', error);} finally {setLoading(false);}
};
  1. 预加载下一页数据
const prefetchNextPage = (current, pageSize) => {const nextPage = current + 1;const cacheKey = `${nextPage}-${pageSize}`;// 如果下一页已缓存或正在加载,则不预加载if (cachedData[cacheKey] || loading) return;// 静默加载下一页axios.get('/api/items', {params: { page: nextPage, pageSize }}).then(response => {setCachedData({...cachedData,[cacheKey]: response.data.items});}).catch(err => {console.error('Prefetch error:', err);});
};// 在数据加载完成后调用预加载
useEffect(() => {if (!loading && data.length > 0) {prefetchNextPage(pagination.current, pagination.pageSize);}
}, [data, loading]);
  1. 处理搜索和筛选
import { Table, Pagination, Input, Form, Button, Select } from 'antd';
import { debounce } from 'lodash';function EnhancedTable() {// ...之前的状态const [filters, setFilters] = useState({});// 使用防抖处理搜索const handleSearch = debounce((searchText) => {setFilters(prev => ({ ...prev, searchText }));fetchData({ current: 1 }); // 搜索时重置到第一页}, 300);const fetchData = async (params = {}) => {setLoading(true);try {const response = await axios.get('/api/items', {params: {page: params.current || pagination.current,pageSize: params.pageSize || pagination.pageSize,...filters // 添加所有筛选条件}});// 更新数据和分页信息// ...} catch (error) {console.error('Error:', error);} finally {setLoading(false);}};return (<><Form layout="inline" style={{ marginBottom: 16 }}><Form.Item label="搜索"><Input.Search placeholder="输入关键词" onSearch={value => handleSearch(value)}onChange={e => handleSearch(e.target.value)}/></Form.Item><Form.Item label="状态"><Selectplaceholder="选择状态"style={{ width: 120 }}onChange={value => {setFilters(prev => ({ ...prev, status: value }));fetchData({ current: 1 });}}allowClear><Select.Option value="active">活跃</Select.Option><Select.Option value="inactive">非活跃</Select.Option></Select></Form.Item></Form><Table// ...之前的Table属性/></>);
}

3. 瀑布流实现 - React Antd

基于Marker/Cursor的瀑布流

import { List, Spin, message } from 'antd';
import { useState, useEffect, useRef } from 'react';
import InfiniteScroll from 'react-infinite-scroll-component';
import axios from 'axios';function InfiniteScrollList() {const [data, setData] = useState([]);const [loading, setLoading] = useState(false);const [hasMore, setHasMore] = useState(true);const marker = useRef(null);const loadMoreData = async () => {if (loading || !hasMore) return;setLoading(true);try {const response = await axios.get('/api/items', {params: {limit: 20,marker: marker.current}});const newData = response.data.data;if (newData.length === 0) {setHasMore(false);} else {setData([...data, ...newData]);marker.current = response.data.marker;// 如果没有返回marker,说明没有更多数据了if (!response.data.marker) {setHasMore(false);}}} catch (error) {console.error('Error fetching data:', error);message.error('加载失败,请重试');setHasMore(false);} finally {setLoading(false);}};useEffect(() => {loadMoreData();}, []);return (<divid="scrollableDiv"style={{height: 400,overflow: 'auto',padding: '0 16px',border: '1px solid rgba(140, 140, 140, 0.35)'}}><InfiniteScrolldataLength={data.length}next={loadMoreData}hasMore={hasMore}loader={<Spin tip="加载中..." />}endMessage={<div style={{ textAlign: 'center' }}>没有更多数据了</div>}scrollableTarget="scrollableDiv"><ListdataSource={data}renderItem={item => (<List.Item key={item.id}><List.Item.Metatitle={item.title}description={item.description}/></List.Item>)}/></InfiniteScroll></div>);
}

虚拟列表优化

对于大量数据,可以结合虚拟列表以提高性能:

import { List, Avatar, Spin } from 'antd';
import { useState, useEffect, useRef } from 'react';
import VirtualList from 'rc-virtual-list';
import axios from 'axios';function VirtualizedInfiniteList() {const [data, setData] = useState([]);const [loading, setLoading] = useState(false);const [hasMore, setHasMore] = useState(true);const marker = useRef(null);const containerRef = useRef(null);const itemHeight = 47; // 每项的高度const loadMoreData = async () => {if (loading || !hasMore) return;setLoading(true);try {const response = await axios.get('/api/items', {params: {limit: 20,marker: marker.current}});const newData = response.data.data;if (newData.length === 0) {setHasMore(false);} else {setData(prevData => [...prevData, ...newData]);marker.current = response.data.marker;if (!response.data.marker) {setHasMore(false);}}} catch (error) {console.error('Error:', error);setHasMore(false);} finally {setLoading(false);}};useEffect(() => {loadMoreData();}, []);const onScroll = (e) => {if (e.target.scrollHeight - e.target.scrollTop <= e.target.clientHeight + 100) {loadMoreData();}};return (<List>{loading && data.length === 0 ? <Spin /> : null}<VirtualListdata={data}height={400}itemHeight={itemHeight}itemKey="id"onScroll={onScroll}ref={containerRef}>{(item) => (<List.Item key={item.id}><List.Item.Metaavatar={<Avatar src={item.avatar} />}title={item.title}description={item.description}/></List.Item>)}</VirtualList>{loading && data.length > 0 ? (<div style={{ textAlign: 'center', padding: '12px 0' }}><Spin /></div>) : null}</List>);
}

4. 优化策略总结

性能优化

  1. 虚拟滚动:仅渲染可见区域内的元素,大幅提升性能

    // 使用React Window (安装: npm install react-window)
    import { FixedSizeList as List } from 'react-window';const Row = ({ index, style }) => (<div style={style}>Row {index}</div>
    );const VirtualizedList = () => (<Listheight={400}itemCount={1000}itemSize={35}width={300}>{Row}</List>
    );
    
  2. 数据预取:提前加载下一页数据,提升用户体验

    // 当用户滚动到接近底部时预加载
    const handleScroll = (e) => {const { scrollTop, scrollHeight, clientHeight } = e.target;// 当滚动到距离底部20%的位置时预加载if (scrollTop > (scrollHeight - clientHeight) * 0.8) {prefetchNextData();}
    };
    
  3. 请求优化:使用防抖和节流控制请求频率

    import { debounce, throttle } from 'lodash';// 防抖:用于搜索输入
    const debouncedSearch = debounce((value) => {fetchData(value);
    }, 300);// 节流:用于滚动事件
    const throttledScroll = throttle((e) => {handleScroll(e);
    }, 200);
    

用户体验优化

  1. 加载状态反馈

    // 使用骨架屏代替简单的加载指示器
    import { Skeleton } from 'antd';{loading ? (<Skeleton active paragraph={{ rows: 4 }} />
    ) : (<ContentComponent data={data} />
    )}
    
  2. 错误处理与重试

    const [error, setError] = useState(null);const fetchData = async () => {setLoading(true);setError(null);try {// 数据请求...} catch (err) {setError(err.message || '加载失败');} finally {setLoading(false);}
    };// 在UI中展示错误信息和重试按钮
    {error && (<div className="error-container"><p>{error}</p><Button onClick={fetchData}>重试</Button></div>
    )}
    
  3. 记住滚动位置

    // 保存滚动位置到sessionStorage
    const saveScrollPosition = () => {sessionStorage.setItem('scrollPosition', container.current.scrollTop);
    };// 组件卸载前保存位置
    useEffect(() => {return () => {saveScrollPosition();};
    }, []);// 组件挂载时恢复位置
    useEffect(() => {const savedPosition = sessionStorage.getItem('scrollPosition');if (savedPosition && container.current) {container.current.scrollTop = parseInt(savedPosition);}
    }, []);
    

5. 最佳实践

分页场景选择

  1. 传统分页(页码导航)适用场景
    • 后台管理系统
    • 数据表格/数据列表展示
    • 需要精确定位到特定页面的场景
    • 数据总量明确的场景
  2. 瀑布流/无限滚动适用场景
    • 社交媒体信息流
    • 图片/卡片展示墙
    • 新闻阅读页面
    • 产品类目浏览
    • 强调浏览体验的场景

实现决策树

选择分页方式
├── 需要精确页码跳转?
│   ├── 是 → 使用传统分页 (Pagination)
│   │   └── 数据量大?
│   │       ├── 是 → 启用虚拟滚动
│   │       └── 否 → 使用标准Table组件
│   └── 否 → 考虑瀑布流/无限滚动
│       ├── 需要保持列表位置?
│       │   ├── 是 → 使用marker/cursor分页
│       │   └── 否 → 可使用offset分页
│       └── 列表项数量可能很大?
│           ├── 是 → 必须启用虚拟滚动
│           └── 否 → 可以使用简单InfiniteScroll

6. React Antd 常用组件示例

完整的Table分页组件(含搜索、筛选、缓存)

import React, { useState, useEffect, useCallback, useMemo } from 'react';
import { Table, Input, Button, Form, Select, Space, message, Card } from 'antd';
import { SearchOutlined, ReloadOutlined } from '@ant-design/icons';
import axios from 'axios';
import { debounce } from 'lodash';const AdvancedPaginationTable = () => {// 状态管理const [data, setData] = useState([]);const [loading, setLoading] = useState(false);const [pagination, setPagination] = useState({current: 1,pageSize: 10,total: 0,showSizeChanger: true,pageSizeOptions: ['10', '20', '50', '100'],showTotal: (total) => `${total} 条数据`});const [filters, setFilters] = useState({});const [cacheData, setCacheData] = useState({});const [form] = Form.useForm();// 生成缓存键const getCacheKey = useCallback((page, pageSize, currentFilters) => {const filtersKey = Object.keys(currentFilters).sort().map(key => `${key}:${currentFilters[key]}`).join('|');return `${page}-${pageSize}-${filtersKey}`;}, []);// 处理数据获取const fetchData = useCallback(async (params = {}) => {const current = params.current || pagination.current;const pageSize = params.pageSize || pagination.pageSize;const currentFilters = params.filters || filters;// 检查缓存中是否有数据const cacheKey = getCacheKey(current, pageSize, currentFilters);if (cacheData[cacheKey]) {setData(cacheData[cacheKey].data);setPagination(prev => ({...prev,current,pageSize,total: cacheData[cacheKey].total}));return;}setLoading(true);try {const response = await axios.get('/api/items', {params: {page: current,pageSize,...currentFilters}});const newData = response.data.items || [];const total = response.data.total || 0;setData(newData);setPagination(prev => ({...prev,current,pageSize,total}));// 更新缓存setCacheData(prev => ({...prev,[cacheKey]: { data: newData, total }}));// 预加载下一页if (current < Math.ceil(total / pageSize)) {prefetchNextPage(current, pageSize, currentFilters);}} catch (error) {console.error('Failed to fetch data:', error);message.error('获取数据失败,请重试');} finally {setLoading(false);}}, [pagination, filters, cacheData, getCacheKey]);// 预加载下一页数据const prefetchNextPage = useCallback((current, pageSize, currentFilters) => {const nextPage = current + 1;const cacheKey = getCacheKey(nextPage, pageSize, currentFilters);// 已缓存则不再请求if (cacheData[cacheKey]) return;// 后台静默加载,不影响当前UIaxios.get('/api/items', {params: {page: nextPage,pageSize,...currentFilters}}).then(response => {setCacheData(prev => ({...prev,[cacheKey]: { data: response.data.items || [], total: response.data.total || 0 }}));}).catch(err => {console.error('预加载下一页失败:', err);});}, [cacheData, getCacheKey]);// 防抖搜索处理const handleSearch = debounce((values) => {const newFilters = {};Object.entries(values).forEach(([key, value]) => {if (value !== undefined && value !== '') {newFilters[key] = value;}});setFilters(newFilters);// 搜索时重置到第一页fetchData({ current: 1, filters: newFilters });}, 300);// 重置筛选const handleReset = () => {form.resetFields();setFilters({});fetchData({ current: 1, filters: {} });};// 处理表格变更 (分页、筛选、排序)const handleTableChange = (pagination, filters, sorter) => {fetchData({current: pagination.current,pageSize: pagination.pageSize,filters: {...form.getFieldsValue(),// 添加表格内置筛选...(filters && Object.keys(filters).length > 0 ? Object.fromEntries(Object.entries(filters).filter(([_, value]) => value && value.length > 0).map(([key, value]) => [key, value.join(',')])) : {}),// 添加排序...(sorter.field ? {sortField: sorter.field,sortOrder: sorter.order} : {})}});};// 初始加载useEffect(() => {fetchData();}, []);// 表格列定义const columns = [{title: 'ID',dataIndex: 'id',key: 'id',width: 80,sorter: true},{title: '名称',dataIndex: 'name',key: 'name',sorter: true,defaultSortOrder: 'ascend'},{title: '状态',dataIndex: 'status',key: 'status',filters: [{ text: '活跃', value: 'active' },{ text: '非活跃', value: 'inactive' }],render: status => (<span style={{ color: status === 'active' ? 'green' : 'gray'}}>{status === 'active' ? '活跃' : '非活跃'}</span>)},{title: '创建时间',dataIndex: 'createdAt',key: 'createdAt',sorter: true},{title: '操作',key: 'action',render: (_, record) => (<Space size="middle"><a onClick={() => console.log('查看', record)}>查看</a><a onClick={() => console.log('编辑', record)}>编辑</a></Space>)}];return (<Card><Formform={form}layout="inline"style={{ marginBottom: 16 }}onFinish={handleSearch}><Form.Item name="keyword" label="关键词"><Input placeholder="搜索名称"prefix={<SearchOutlined />}allowClearonChange={e => form.submit()}/></Form.Item><Form.Item name="dateRange" label="日期范围"><Selectstyle={{ width: 200 }}placeholder="选择日期范围"allowClearonChange={() => form.submit()}><Select.Option value="today">今天</Select.Option><Select.Option value="week">最近一周</Select.Option><Select.Option value="month">最近一个月</Select.Option></Select></Form.Item><Form.Item><Button icon={<ReloadOutlined />} onClick={handleReset}>重置</Button></Form.Item></Form><Tablecolumns={columns}dataSource={data}rowKey="id"pagination={pagination}loading={loading}onChange={handleTableChange}scroll={{ x: 800 }}/></Card>);
};export default AdvancedPaginationTable;

高性能瀑布流组件(虚拟滚动+Marker分页)

import React, { useState, useEffect, useRef, useCallback } from 'react';
import { List, Card, Avatar, Spin, Empty, Button, message } from 'antd';
import { ReloadOutlined } from '@ant-design/icons';
import VirtualList from 'rc-virtual-list';
import axios from 'axios';
import { throttle } from 'lodash';const ITEM_HEIGHT = 180; // 每个卡片高度
const CONTAINER_HEIGHT = 600; // 容器高度
const BATCH_SIZE = 15; // 每次加载条数const HighPerformanceInfiniteScroll = () => {const [data, setData] = useState([]);const [loading, setLoading] = useState(false);const [initialLoading, setInitialLoading] = useState(true);const [error, setError] = useState(null);const [hasMore, setHasMore] = useState(true);const markerRef = useRef(null);const containerRef = useRef(null);// 加载数据的核心函数const loadData = useCallback(async (reset = false) => {// 如果已在加载或没有更多数据,则跳过if ((loading && !reset) || (!hasMore && !reset)) return;try {setLoading(true);if (reset) {setInitialLoading(true);setError(null);markerRef.current = null;}const response = await axios.get('/api/feed', {params: {limit: BATCH_SIZE,marker: reset ? null : markerRef.current}});const { items, marker } = response.data;if (items && items.length > 0) {setData(prevData => reset ? items : [...prevData, ...items]);markerRef.current = marker;setHasMore(!!marker); // 如果没有返回marker,表示没有更多数据} else {setHasMore(false);}} catch (err) {console.error('Failed to fetch data:', err);setError('加载数据失败,请重试');setHasMore(false);} finally {setLoading(false);setInitialLoading(false);}}, [loading, hasMore]);// 初始加载useEffect(() => {loadData(true);}, []);// 保存滚动位置useEffect(() => {const saveScrollPosition = () => {if (containerRef.current) {sessionStorage.setItem('infiniteScrollPos', containerRef.current.scrollTop);}};// 页面关闭或组件卸载时保存位置window.addEventListener('beforeunload', saveScrollPosition);return () => {saveScrollPosition();window.removeEventListener('beforeunload', saveScrollPosition);};}, []);// 恢复滚动位置useEffect(() => {const savedPosition = sessionStorage.getItem('infiniteScrollPos');if (savedPosition && containerRef.current && data.length > 0) {setTimeout(() => {containerRef.current.scrollTop = parseInt(savedPosition);}, 100);}}, [initialLoading, data.length]);// 节流处理的滚动事件const onScroll = throttle(e => {if (e.target.scrollHeight - e.target.scrollTop

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

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

相关文章

Linux网络编程:TCP多进程/多线程并发服务器详解

Linux网络编程&#xff1a;TCP多进程/多线程并发服务器详解 TCP并发服务器概述 在Linux网络编程中&#xff0c;TCP服务器主要有三种并发模型&#xff1a; 多进程模型&#xff1a;为每个客户端连接创建新进程多线程模型&#xff1a;为每个客户端连接创建新线程I/O多路复用&am…

详解springcloudalibaba采用prometheus+grafana实现服务监控

文章目录 1.官网下载安装 prometheus和grafana1.promethus2.grafana 2. 搭建springcloudalibaba集成prometheus、grafana1. 引入依赖,springboot3.2之后引入如下2. 在yml文件配置监控端点暴露配置3. 在当前启动的应用代码中添加&#xff0c;在prometheus显示的时候附加当前应用…

数据分析1

一、常用数据处理模块Numpy Numpy常用于高性能计算&#xff0c;在机器学习常常作为传递数据的容器。提供了两种基本对象&#xff1a;ndarray、ufunc。 ndarray具有矢量算术运算和复杂广播能力的快速且节省空间的多维数组。 ufunc提供了对数组快速运算的标准数学函数。 ndar…

DeepSeek智能时空数据分析(六):大模型NL2SQL绘制城市之间连线

序言&#xff1a;时空数据分析很有用&#xff0c;但是GIS/时空数据库技术门槛太高 时空数据分析在优化业务运营中至关重要&#xff0c;然而&#xff0c;三大挑战仍制约其发展&#xff1a;技术门槛高&#xff0c;需融合GIS理论、SQL开发与时空数据库等多领域知识&#xff1b;空…

2023ICPC合肥题解

文章目录 F. Colorful Balloons(签到)E. Matrix Distances(思维小结论)J. Takeout Delivering(最短路)G. Streak Manipulation(二分dp)C. Cyclic Substrings(回文自动机) 题目链接 F. Colorful Balloons(签到) int n;cin>>n;for(int i1;i<n;i) cin>>s[i];map<…

数字技术驱动下教育生态重构:从信息化整合到数字化转型的路径探究

一、引言 &#xff08;一&#xff09;研究背景与问题提出 在当今时代&#xff0c;数字技术正以前所未有的速度和深度渗透到社会的各个领域&#xff0c;教育领域也不例外。从早期的教育信息化整合到如今的数字化转型&#xff0c;教育系统正经历着一场深刻的范式变革。 回顾教…

terraform 动态块(Dynamic Blocks)详解与实践

在 Terraform 中&#xff0c;动态块&#xff08;Dynamic Blocks&#xff09; 是一种强大的机制&#xff0c;允许你根据变量或表达式动态生成配置块&#xff0c;避免重复编写相似的代码。这在处理需要重复定义的结构&#xff08;如资源参数、嵌套配置&#xff09;时特别有用。以…

Unity3D引擎框架及用户接口调用方式相关分析及汇总

分析目的 目前外网3D手游绝大部基于Unity3D引擎进行开发,Unity3D引擎属于商业引擎,引擎整理框架的运行机制较为神秘,本文介绍Unity引擎框架、对象组织方式、用户接口与引擎交互方式等原理,通过本文的分析和介绍可了解Unity3D框架中大致执行原理。 实现原理 Unity引擎作为…

react-09React生命周期

1.react生命周期&#xff08;旧版&#xff09; 1.1react初始挂载时的生命周期 1:构造器-constructor // 构造器constructor(props) {console.log(1:构造器-constructor);super(props)// 初始化状态this.state {count: 0}} 2:组件将要挂载-componentWillMount // 组件将要挂载…

【NVM】管理不同版本的node.js

目录 一、下载nvm 二、安装nvm 三、验证安装 四、配置下载镜像 五、使用NVM 前言&#xff1a;不同的node.js版本会让你在使用过程很费劲&#xff0c;nvm是一个node版本管理工具&#xff0c;通过它可以安装多种node版本并且可以快速、简单的切换node版本。 一、下载nvm htt…

八大排序——冒泡排序/归并排序

八大排序——冒泡排序/归并排序 一、冒泡排序 1.1 冒泡排序 1.2 冒泡排序优化 二、归并排序 1.1 归并排序&#xff08;递归&#xff09; 1.2 递归排序&#xff08;非递归&#xff09; 一、冒泡排序 1.1 冒泡排序 比较相邻的元素。如果第一个比第二个大&#xff0c;就交换…

区块链随学随记

前情提要&#xff1a;本人技术栈为ganachehardhatpython ganache提供的是本地的区块链环境&#xff0c;相当于模拟以太坊&#xff0c;这样可以允许多个账户在本机交互。hardhat和remix都是区块链ide&#xff0c;用于编写和部署合约助记词有个数规定&#xff0c;只有满足这些个数…

Android原生开发基础

Android实战 Android 原生开发基础 知识点1 介绍了解2 系统体系架构3 四大应用组件4 移动操作系统优缺点5 开发工具6 配置工具7 下载相关资源8JDK下载安装流程9配置好SDK和JDK环境10 第一个Hello word11 AS开发前常用设置12模拟器使用运行13 真机调试14 AndroidUI基础布局15 加…

网页版 deepseek 对话问答内容导出为 PDF 文件和 Word 文件的浏览器插件下载安装和使用说明

文章目录 网页版 deepseek 浏览器扩展应用程序插件1. 预览效果2. 功能介绍3. 浏览器扩展应用程序下载3.1. 下载方式13.2. 下载方式24. 安装教程4.1. Chrome 浏览器安装步骤4.2. Edge 浏览器安装步骤5. 使用说明网页版 deepseek 浏览器扩展应用程序插件 1. 预览效果 预览效果 导…

DBdriver使用taos数据库

首先创建连接 连接后比如数据库里有三个库 选择其中的hypon 选中localhost&#xff0c;右键sql编辑器&#xff0c;打开sql控制台 就插入了一条数据

【前端】【面试】如何实现图片渐进式加载?有几种方法

前端图片渐进式加载 一、技术原理解析 渐进式加载是通过分阶段、按需加载图片&#xff0c;以提升用户体验和页面性能的优化技术。主要包括以下实现方式&#xff1a; 懒加载&#xff1a;基于IntersectionObserver API&#xff0c;当图片进入浏览器视口时才发起加载请求&#…

Spring Boot 中的条件注解

Spring Boot条件注解的汇总&#xff1a; 注解作用判断依据使用场景ConditionalOnBean容器中存在指定Bean时&#xff0c;被注解的配置或Bean定义生效指定Bean在容器中存在依赖其他已存在Bean时配置相关功能ConditionalOnCheckpointRestore在特定检查点恢复相关条件满足时生效满…

leetcode11-盛水最多的容器

leetcode 11 思路 问题分析 拆解问题&#xff0c;面积 底 * 高 宽度&#xff1a;两个竖直线之间的距离&#xff0c;显然是 right - left高度&#xff1a;容器的水位受限于较短的那根竖直线的高度&#xff0c;所以高度为 min(height[left], height[right]) 本题其实很容易…

HTTP:十二.HTTPS

HTTPS 概述 超文本传输安全协议(英语:HyperText Transfer Protocol Secure,缩写:HTTPS;常称为HTTP over TLS、HTTP over SSL或HTTP Secure)是一种通过计算机网络进行安全通信的传输协议。HTTPS经由HTTP进行通信,利用TLS加密数据包。 HTTPS的主要目的是提供对网站服务器…

MySQL数据库(14)—— 使用C操作MySQL

目录 一&#xff0c;下载库 二&#xff0c;安装库 三&#xff0c;使用库 3.1 连接数据库 3.2 发送SQL 3.3 获取结果 问题&#xff1a;为什么不使用C&#xff1f; 解答&#xff1a;使用C的库已经可以完成绝大部分MySQL操作了&#xff0c;并且C的库的使用更加复杂&#xff…