最终效果

在这里插入图片描述

顶栏

在这里插入图片描述

modules/index/components/topBar.tsx

import icon_daily from "@/assets/images/icon_daily.png";
import MaterialIcons from "@expo/vector-icons/MaterialIcons";
import { useCallback, useState } from "react";
import { Image, StyleSheet, Text, TouchableOpacity, View } from "react-native";
export default function IndexTopBar() {const [tab, setTab] = useState("关注");const tabList = [{label: "关注",},{label: "发现",},{label: "成都",},];const handlePress = useCallback((item: string) => {setTab(item);}, []);return (<View style={styles.container}><TouchableOpacity style={styles.dailyButton}><Image style={styles.icon} source={icon_daily} /></TouchableOpacity><View style={styles.typeBox}>{tabList.map((item) => (<TouchableOpacityactiveOpacity={0.5}onPress={() => handlePress(item.label)}key={item.label}style={[styles.itemBox, tab === item.label && styles.activeItemBox]}><Textstyle={[styles.itemText,tab === item.label && styles.activeItemText,]}>{item.label}</Text></TouchableOpacity>))}</View><MaterialIcons name="search" size={24} color="black" /></View>);
}
const styles = StyleSheet.create({container: {width: "100%",flexDirection: "row",alignItems: "center",justifyContent: "space-between",paddingHorizontal: 12,paddingVertical: 6,borderBottomWidth: 1,borderBottomColor: "#f5f5f5",backgroundColor: "#fff",},icon: {width: 28,height: 28,},dailyButton: {justifyContent: "center",alignItems: "center",},typeBox: {flexDirection: "row",justifyContent: "space-between",alignItems: "center",},itemBox: {marginHorizontal: 12,paddingVertical: 4,},activeItemBox: {borderBottomWidth: 3,borderBottomColor: "#ff2442",},itemText: {fontSize: 16,color: "#999",},activeItemText: {fontSize: 17,color: "#333",},
});

首页导入

app/(tabs)/index.tsx

import TopBar from "@/modules/index/components/topBar";
<TopBar />

频道栏(含编辑弹窗)

在这里插入图片描述

编辑弹窗

在这里插入图片描述

modules/index/components/typeBar.tsx

import MaterialIcons from "@expo/vector-icons/MaterialIcons";
import { useCallback, useEffect, useRef, useState } from "react";
import {ScrollView,StyleSheet,Text,TouchableOpacity,View,
} from "react-native";
import TypeModal from "./typeModal";
type Props = {allCategoryList: Category[];onCategoryChange: (category: Category) => void;
};
// eslint-disable-next-line react/display-name
export default ({ allCategoryList, onCategoryChange }: Props) => {const modalRef = useRef<{show: () => void;hide: () => void;}>(null);const [category, setCategory] = useState<Category>();const [myTypeList, setMyTypeList] = useState<Category[]>([]);useEffect(() => {setMyTypeList(allCategoryList.filter((i) => i.isAdd));setCategory(myTypeList.find((i) => i.name === "推荐"));}, []);const onAllCategoryListChange = (categoryList: Category[]) => {setMyTypeList(categoryList.filter((i) => i.isAdd));};const handlePress = useCallback((item: Category) => {setCategory(item);onCategoryChange(item);}, []);return (<View style={styles.container}><ScrollViewhorizontalkeyboardDismissMode="on-drag"scrollEventThrottle={16}>{myTypeList.map((item, index) => (<TouchableOpacitykey={index}style={styles.itemBox}onPress={() => handlePress(item)}><Textstyle={[styles.itemText,category?.name === item.name && styles.activeItemText,]}>{item.name}</Text></TouchableOpacity>))}</ScrollView><TouchableOpacity onPress={() => modalRef.current?.show()}><MaterialIcons name="keyboard-arrow-down" size={24} color="black" /></TouchableOpacity><TypeModalref={modalRef}categoryList={allCategoryList}onCategoryListChange={onAllCategoryListChange}/></View>);
};
const styles = StyleSheet.create({container: {flexDirection: "row",paddingHorizontal: 12,paddingVertical: 6,backgroundColor: "#fff",},scrollBox: {marginHorizontal: 12,paddingVertical: 4,},itemBox: {paddingRight: 26,},itemText: {fontSize: 16,color: "#999",},activeItemText: {fontSize: 16,color: "#333",fontWeight: "bold",},
});

modules/index/components/typeModal.tsx

import { save } from "@/utils/Storage";
import AntDesign from "@expo/vector-icons/AntDesign";
import MaterialIcons from "@expo/vector-icons/MaterialIcons";
import { forwardRef, useEffect, useImperativeHandle, useState } from "react";
import {Dimensions,Modal,StyleSheet,Text,TouchableOpacity,View,
} from "react-native";
const { width: SCREEN_WIDTH } = Dimensions.get("window");
type Props = {categoryList: Category[];onCategoryListChange: (categoryList: Category[]) => void;
};
// eslint-disable-next-line react/display-name
export default forwardRef(({ categoryList, onCategoryListChange }: Props, ref) => {const [visible, setVisible] = useState(false);const [edit, setEdit] = useState<boolean>(false);const [myList, setMyList] = useState<Category[]>([]);const [otherList, setOtherList] = useState<Category[]>([]);useEffect(() => {if (!categoryList) {return;}const list1 = categoryList.filter((i) => i.isAdd);const list2 = categoryList.filter((i) => !i.isAdd);setMyList(list1);setOtherList(list2);}, [categoryList]);const hide = () => {setVisible(false);};const saveChanges = () => {const newCategoryList = [...myList, ...otherList];save("categoryList", JSON.stringify(newCategoryList));onCategoryListChange(newCategoryList);};const show = () => {setVisible(true);};const delItem = (item: Category) => {const newMyList = myList.filter((i) => i.name !== item.name);const item_copy = { ...item, isAdd: false };const newOtherList = [...otherList, item_copy];setMyList(newMyList);setOtherList(newOtherList);};const addItem = (item: Category) => {if (!edit) {return;}const newOtherList = otherList.filter((i) => i.name !== item.name);const item_copy = { ...item, isAdd: true };const newMyList = [...myList, item_copy];setMyList(newMyList);setOtherList(newOtherList);};// 暴露方法给父组件useImperativeHandle(ref, () => ({show,}));return (<ModalanimationType="fade"transparent={true}visible={visible}onRequestClose={hide}><View style={styles.winBox}><View style={styles.contentBox}><View style={styles.titleBox}><Text style={styles.titleTxt}>我的频道</Text><Text style={styles.subTitleTxt}>{edit ? "点击移除频道" : "点击进入频道"}</Text><TouchableOpacitystyle={styles.editButton}onPress={() => {if (edit) {saveChanges();}setEdit(!edit);}}><Text style={styles.editTxt}>{edit ? "完成编辑" : "进入编辑"}</Text></TouchableOpacity><TouchableOpacity onPress={() => hide()}><MaterialIconsname="keyboard-arrow-up"size={24}color="black"/></TouchableOpacity></View><View style={styles.listBox}>{myList.map((item: Category, index: number) => {return (<TouchableOpacitykey={`${item.name}`}style={item.default? styles.itemLayoutDefault: styles.itemLayout}onPress={() => {if (edit && !item.default) {delItem(item);}}}><Text style={styles.itemTxt}>{item.name}</Text>{edit && !item.default && (<AntDesignstyle={styles.delIcon}name="closecircle"size={14}color="#cecece"/>)}</TouchableOpacity>);})}</View><View style={styles.otherBox}><View style={styles.titleBox}><Text style={styles.titleTxt}>推荐频道</Text><Text style={styles.subTitleTxt}>点击添加频道</Text></View><View style={styles.listBox}>{otherList.map((item: Category, index: number) => {return (<TouchableOpacitykey={`${item.name}`}style={item.default? styles.itemLayoutDefault: styles.itemLayout}onPress={() => {addItem(item);}}><Text style={styles.itemTxt}> + {item.name}</Text></TouchableOpacity>);})}</View></View></View><View style={styles.bottomBox}></View></View></Modal>);}
);
const styles = StyleSheet.create({winBox: {flex: 1,alignItems: "center",backgroundColor: "transparent",},contentBox: {marginTop: 56,width: "100%",backgroundColor: "#fff",},titleBox: {flexDirection: "row",alignItems: "center",paddingHorizontal: 12,},titleTxt: {fontSize: 16,color: "#333",fontWeight: "bold",marginLeft: 6,},subTitleTxt: {fontSize: 13,color: "#999",marginLeft: 12,flex: 1,},bottomBox: {flex: 1,width: "100%",backgroundColor: "rgba(0,0,0,0.5)",},editButton: {paddingHorizontal: 10,height: 28,backgroundColor: "#EEE",borderRadius: 14,justifyContent: "center",alignItems: "center",marginRight: 6,},editTxt: {fontSize: 13,},listBox: {marginTop: 6,width: "100%",flexDirection: "row",flexWrap: "wrap",},itemLayout: {width: (SCREEN_WIDTH - 80) >> 2,height: 32,justifyContent: "center",alignItems: "center",borderWidth: 1,borderColor: "#f5f5f5",borderRadius: 6,marginLeft: 16,marginTop: 12,},itemLayoutDefault: {width: (SCREEN_WIDTH - 80) >> 2,height: 32,justifyContent: "center",alignItems: "center",backgroundColor: "#f5f5f5",borderRadius: 6,marginLeft: 16,marginTop: 12,},itemTxt: {fontSize: 14,color: "#666",},otherBox: {marginVertical: 30,},delIcon: {position: "absolute",right: -6,top: -6,},
});

首页导入

import TypeBar from "@/modules/index/components/typeBar";

作为列表的页眉渲染

        // 列表顶部renderHeader={() =>(!isLoading_type && (<TypeBarallCategoryList={store.categoryList}onCategoryChange={(category: Category) => {console.log(JSON.stringify(category));}}/>)) || <></>}

数据来自 store

import IndexStore from "@/modules/index/IndexStore";
const store = useLocalObservable(() => new IndexStore());

因数据是异步加载,需跟进其加载状态

const [isLoading_type, setIsLoading_type] = useState(true);

在页面初始渲染时异步加载数据

  useEffect(() => {const Loading_type = async () => {try {await store.getCategoryList();} catch (error) {console.error("Failed to fetch category list:", error);} finally {setIsLoading_type(false);}};Loading_type();store.requestHomeList();}, []);

modules/index/IndexStore.ts

暂用的 mock 数据,解开注释,可访问真实接口。

import articles from "@/mock/articles";
import { load } from "@/utils/Storage";
import { Toast } from "@ant-design/react-native";
import { action, observable } from "mobx";
const SIZE = 10;
export default class IndexStore {page: number = 1;@observable homeList: ArticleSimple[] = [];@observable refreshing: boolean = false;@observable categoryList: Category[] = [];@actionresetPage = () => {this.page = 1;};requestHomeList = async () => {if (this.refreshing) {return;}const loading = Toast.loading("加载中...");try {this.refreshing = true;const params = {page: this.page,size: SIZE,};// const { data } = await request("homeList", params);let data = articles.map((item) => ({...item,image: item.images[0],}));if (data?.length) {if (this.page === 1) {this.homeList = data;} else {// this.homeList = [...this.homeList, ...data];}this.page = this.page + 1;} else {if (this.page === 1) {this.homeList = [];} else {// 已经加载完了,没有更多数据}}} catch (error) {console.log(error);} finally {this.refreshing = false;Toast.remove(loading);}};getCategoryList = async () => {const cacheListStr = await load("categoryList");if (cacheListStr) {const cacheList = JSON.parse(cacheListStr);if (cacheList?.length) {this.categoryList = cacheList;} else {this.categoryList = DEFAULT_CATEGORY_LIST;}} else {this.categoryList = DEFAULT_CATEGORY_LIST;}};
}
const DEFAULT_CATEGORY_LIST: Category[] = [// 默认添加频道{ name: "推荐", default: true, isAdd: true },{ name: "视频", default: true, isAdd: true },{ name: "直播", default: true, isAdd: true },{ name: "摄影", default: false, isAdd: true },{ name: "穿搭", default: false, isAdd: true },{ name: "读书", default: false, isAdd: true },{ name: "影视", default: false, isAdd: true },{ name: "科技", default: false, isAdd: true },{ name: "健身", default: false, isAdd: true },{ name: "科普", default: false, isAdd: true },{ name: "美食", default: false, isAdd: true },{ name: "情感", default: false, isAdd: true },{ name: "舞蹈", default: false, isAdd: true },{ name: "学习", default: false, isAdd: true },{ name: "男士", default: false, isAdd: true },{ name: "搞笑", default: false, isAdd: true },{ name: "汽车", default: false, isAdd: true },{ name: "职场", default: false, isAdd: true },{ name: "运动", default: false, isAdd: true },{ name: "旅行", default: false, isAdd: true },{ name: "音乐", default: false, isAdd: true },{ name: "护肤", default: false, isAdd: true },{ name: "动漫", default: false, isAdd: true },{ name: "游戏", default: false, isAdd: true },// 默认添加频道{ name: "家装", default: false, isAdd: false },{ name: "心理", default: false, isAdd: false },{ name: "户外", default: false, isAdd: false },{ name: "手工", default: false, isAdd: false },{ name: "减脂", default: false, isAdd: false },{ name: "校园", default: false, isAdd: false },{ name: "社科", default: false, isAdd: false },{ name: "露营", default: false, isAdd: false },{ name: "文化", default: false, isAdd: false },{ name: "机车", default: false, isAdd: false },{ name: "艺术", default: false, isAdd: false },{ name: "婚姻", default: false, isAdd: false },{ name: "家居", default: false, isAdd: false },{ name: "母婴", default: false, isAdd: false },{ name: "绘画", default: false, isAdd: false },{ name: "壁纸", default: false, isAdd: false },{ name: "头像", default: false, isAdd: false },
];

瀑布流布局列表

https://blog.csdn.net/weixin_41192489/article/details/149202367

首页最终代码

app/(tabs)/index.tsx

import Heart from "@/components/Heart";
import ResizeImage from "@/components/ResizeImage";
import articleList from "@/mock/articleList";
import TopBar from "@/modules/index/components/topBar";
import TypeBar from "@/modules/index/components/typeBar";
import IndexStore from "@/modules/index/IndexStore";
import { useRouter } from "expo-router";
import { observer, useLocalObservable } from "mobx-react-lite";
import { useCallback, useEffect, useState } from "react";
import {Dimensions,Image,StyleSheet,Text,TouchableOpacity,View,
} from "react-native";
import WaterfallFlow from "../../components/WaterfallFlow";
const { width: SCREEN_WIDTH } = Dimensions.get("window");
export default observer(function IndexScreen() {const router = useRouter();const store = useLocalObservable(() => new IndexStore());const [isLoading_type, setIsLoading_type] = useState(true);useEffect(() => {const Loading_type = async () => {try {await store.getCategoryList();} catch (error) {console.error("Failed to fetch category list:", error);} finally {setIsLoading_type(false);}};Loading_type();store.requestHomeList();}, []);const onArticlePress = useCallback((article: ArticleSimple) => () => {router.push(`/articleDetail?id=${article.id}`);},[]);const renderItem = (item: ArticleSimple) => {return (<TouchableOpacity style={styles.item} onPress={onArticlePress(item)}><ResizeImage uri={item.image} /><Text style={styles.titleTxt}>{item.title}</Text><View style={[styles.nameLayout]}><Image style={styles.avatarImg} source={{ uri: item.avatarUrl }} /><Text style={styles.nameTxt}>{item.userName}</Text><Heartvalue={item.isFavorite}onValueChanged={(value: boolean) => {console.log(value);}}/><Text style={styles.countTxt}>{item.favoriteCount}</Text></View></TouchableOpacity>);};const loadMoreData = () => {store.requestHomeList();};const refreshNewData = () => {store.resetPage();store.requestHomeList();};const Footer = () => {return <Text style={styles.footerTxt}>---- 没有更多数据了 ---- </Text>;};return (<View style={styles.page}><TopBar /><WaterfallFlowdata={articleList}// 列数numColumns={2}// 列间距columnGap={8}// 行间距rowGap={4}// 触顶下拉刷新onRefresh={refreshNewData}// 触底加载更多数据onLoadMore={loadMoreData}// 是否在刷新refreshing={store.refreshing}// 列表顶部renderHeader={() =>(!isLoading_type && (<TypeBarallCategoryList={store.categoryList}onCategoryChange={(category: Category) => {console.log(JSON.stringify(category));}}/>)) || <></>}// 列表项renderItem={renderItem}// 列表底部renderFooter={Footer}/></View>);
});
const styles = StyleSheet.create({page: {paddingBottom: 50,},item: {width: (SCREEN_WIDTH - 18) >> 1,backgroundColor: "white",marginLeft: 6,marginBottom: 6,borderRadius: 8,overflow: "hidden",},countTxt: {fontSize: 14,color: "#999",marginLeft: 4,},titleTxt: {fontSize: 14,color: "#333",marginHorizontal: 10,marginVertical: 4,},nameLayout: {width: "100%",flexDirection: "row",alignItems: "center",paddingHorizontal: 10,marginBottom: 10,},avatarImg: {width: 20,height: 20,resizeMode: "cover",borderRadius: 10,},nameTxt: {fontSize: 12,color: "#999",marginLeft: 6,flex: 1,},footerTxt: {width: "100%",fontSize: 14,color: "#999",marginVertical: 16,textAlign: "center",textAlignVertical: "center",},
});

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

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

相关文章

告别Root风险:四步构建安全高效的服务器管理体系

当整个开发团队都使用root账号操作服务器&#xff0c;且重要数据无备份时&#xff0c;系统如同行走在悬崖边缘。本文将分享一套经过验证的四步解决方案&#xff0c;帮助团队快速提升主机安全性。 为什么必须告别Root账号&#xff1f; 直接使用root账号的风险&#xff1a; &am…

【IM项目笔记】1、WebSocket协议和服务端推送Web方案

这里写自定义目录标题 1、HTTP和WebSocket协议2、WebSocket3、Http VS WebSocket4、WebSocket - 建立连接5、服务端推送Web方案(1) 短轮询(2) 长轮询(3) WebSocket长连接1、HTTP和WebSocket协议 📕 HTTP请求的特点:通信只能由客户端发起。所以,早期很多网站为了实现推送技…

【深度学习新浪潮】什么是上下文长度?

大型语言模型(LLM)的上下文长度是指模型在处理当前输入时能够有效利用的历史文本长度,通常以token(如单词、子词或标点)为单位衡量。例如,GPT-4支持128K token的上下文,而Llama 4 Scout甚至达到了10M token的惊人规模。这一指标直接影响模型在长文档理解、多轮对话等复杂…

Modbus TCP转Profibus网关轻松让流量计与DCS通讯

Modbus TCP转Profibus网关轻松让流量计与DCS通讯工业自动化系统中&#xff0c;协议差异常成为设备互联的“语言障碍”。例如&#xff0c;当流量计采用Modbus TCP协议&#xff0c;而DCS系统仅支持Profibus DP时&#xff0c;如何实现无缝通信&#xff1f;本文将结合技术原理与真实…

云时代下的IT资产管理自动化实践

前言伴随着企业数字化转型进程的加快&#xff0c;IT资产规模日益庞大且复杂。传统的手工IT资产登记、跟踪与管理方式&#xff0c;效率低下且容易出错&#xff0c;已经无法满足现代企业对于敏捷化、可视化和自动化运维的需求。云计算、容器化、微服务架构的普及又进一步加快了资…

Windows主机远程桌面连接Ubuntu24.04主机

最近刚刚换了台新电脑&#xff0c;想着空出老电脑直接装一个Ubuntu系统给新电脑远程连接过去进行开发&#xff0c;就可以完美避开双系统老是要重启切换的问题。仔细一查发现Ubuntu24.04自带了RDP远程工具&#xff0c;大喜&#xff01;于是探究了一番。 本篇文章将介绍本人探究…

Android WebView 性能优化指南

Android WebView 性能优化指南 WebView优化需要从多个维度综合考虑&#xff1a;优化维度关键措施预期收益初始化延迟加载、实例复用降低内存峰值渲染硬件加速、合理布局提升流畅度20%内存独立进程、泄漏防护减少OOM风险网络缓存策略、资源拦截节省流量30%安全漏洞修复、接口限制…

Linux下SPHinXsys源码编译安装及使用

目录 软件介绍 基本依赖 一、源码下载 二、安装依赖库 1、BLAS 2、LAPACK 3、oneTBB 4、googletest 5、Boost 6、Simbody 7、pybind11 8、Eigen3 三、解压缩 四、编译安装 软件介绍 SPHinXsys是胡湘渝博士团队采用C/C开发的一个开源无网格、多分辨率、多物理场、…

Linux中的静态库和动态库

首先 我们要明白什么是库? 库&#xff08;Library&#xff09;是一组预编译的代码&#xff0c;提供特定的功能&#xff0c;可以被多个程序共享调用&#xff0c;避免重复编写代码。在链接步骤中&#xff0c;链接器将从库文件取得所需的代码&#xff0c;复制到生成的可执行文件中…

Vue3-组件化-Vue核心思想之一

一.组件及组件化1.组件化的作用由于之前的代码全写在一个App.vue这个文件里面&#xff0c;会到导致一个文件代码过于多而且不易复用&#xff0c;所以有组件化的思想。2.组件的使用①创建创建一个.vue文件&#xff0c;使用setup的简写方式会自动导出.vue文件②导入import 组件对…

OS学习笔记

《几个基本知识点》 一、2的幂 1024210 51229 25628 12827 6426 3225 1624 823 422 221 K210 G220 M230 T240 P250 E260 Z270 Y280 R290 Q2100 二、常用的ASCII码 ‘1’0x31 ‘A’0x41 ‘a’0x61 空格0x20 换行0x0A 回车0x0D 三、存储器层次中的典型速度 CPU/寄存器&#xff1a…

嵌入式学习笔记-MCU阶段-DAY01

恭喜大家完成了C语言的学习&#xff0c;现在咱们来到咱们的硬件MCU阶段&#xff0c;咱们这里的工程用的是keil&#xff0c;环境搭建不再赘述&#xff0c;希望大家在这一阶段仍然学的愉快 1.资料部分 用的最多的就是STM32f103的手册&#xff0c;搭配STM32F103ZET6的开发板 2.概…

three案例 Three.js波纹效果演示

波纹效果&#xff0c;在智慧城市可视化开发中经常用到&#xff0c;这里分享一个比较好玩的案例 以下是详细的步骤&#xff1a; 初始化部分&#xff1a;设置 Three.js 环境&#xff0c;包括场景、相机、渲染器和控制器 几何体和纹理&#xff1a;创建平面几何体并加载波纹纹理 着…

Flutter-详解布局

上一章我们详细的学习了 Flutter 中的Widget&#xff0c;这一章我们将要学习 Flutter 的布局&#xff0c; 在上一章我们了解到了&#xff1a;Everything is a widget&#xff0c;在 Flutter 中几乎所有的对象都是一个 Widget &#xff0c;当然也包括布局&#xff0c;Flutter 的…

EPLAN 电气制图:建立自己的部件库,添加部件-加SQL Server安装教程(三)上

在智能电气设计领域&#xff0c;EPLAN 作为主流的设计软件&#xff0c;其部件库的完善程度直接影响项目设计的效率与质量。本文将从实际操作出发&#xff0c;详细讲解如何在 EPLAN 中建立专属部件库并添加部件&#xff0c;为电气设计奠定坚实基础。一、部件库&#xff1a;电气设…

静态路由进阶实战全解

一、项目背景二、项目拓扑图三、设备命名与IP地址规划设备名接口编号IP地址规划R1GE0/0192.168.1.1/24GE0/1172.16.1.1/24R2GE0/0192.168.1.2/24GE0/1192.168.2.2/24R3GE0/0192.168.2.3/24GE0/1192.168.3.3/24GE0/2192.168.4.3/24R4GE0/0192.168.3.4/24GE0/1192.168.4.4/24GE0/…

stm32hal模块驱动(3)ssd1305 oled驱动

SD1305 OLED 驱动芯片详细介绍SSD1305 是 Solomon Systech 公司生产的一款 OLED 显示控制器/驱动器&#xff0c;专为 128x64 或 128x32 点阵的 OLED 显示屏设计。下面我将从多个方面详细介绍这款驱动芯片。一、SSD1305 基本特性显示分辨率&#xff1a;最大支持 128 segments 6…

安全为先:如何在 Python 中安全处理数据库连接与敏感信息

安全为先:如何在 Python 中安全处理数据库连接与敏感信息 引言:Python 与安全的数据库交互 自 1991 年诞生以来,Python 凭借其简洁优雅的语法和强大的生态系统,成为 Web 开发、数据科学、人工智能和数据库交互的首选语言。作为“胶水语言”,Python 不仅让开发者能够快速…

服务器经常出现蓝屏是什么原因导致的?如何排查和修复?

服务器出现蓝屏&#xff08;BSOD&#xff0c;Blue Screen of Death&#xff09;是一个严重的问题&#xff0c;通常表明系统内核或硬件发生了不可恢复的错误。蓝屏不仅会导致服务器宕机&#xff0c;还可能对业务运行造成重大影响。要有效解决蓝屏问题&#xff0c;需要先找到根本…

为什么elementui的<el-table-column label=“名称“ prop=“name“ label不用写成:label

在 Vue.js 中&#xff0c;label 和 prop 是 el-table-column 组件的普通属性&#xff0c;而不是动态绑定的表达式。因此&#xff0c;不需要使用 : 来绑定它们。 1. Vue.js 中的属性绑定 在 Vue.js 中&#xff0c;属性绑定有两种方式&#xff1a; 静态属性绑定&#xff1a;直接写…