ReactNative【實戰系列教程】我的小紅書 4 -- 首頁(含頂欄tab切換,橫向滾動頻道,頻道編輯彈窗,瀑布流布局列表等)

最終效果

在這里插入圖片描述

頂欄

在這里插入圖片描述

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;直接寫…