使用Nextjs学习(学习+项目完整版本)
创建项目
运行如下命令
npx create-next-app next-create
创建项目中出现的各种提示直接走默认的就行,一直回车就行了
创建完成后进入到项目运行localhost:3000访问页面,如果和我下面页面一样就是创建项目成功了
整理项目
- 将app/globals.css里面的样式都删除,只留下最上面三行即可
- 将app/layout.js的类名添加一个补充,换成 className={
${inter.className} h-screen
} 相当于给了高度100vh撑满
页面与布局
将app/Layout.js进行改造
import { Inter } from "next/font/google";
import "./globals.css";const inter = Inter({ subsets: ["latin"] });export const metadata = {title: "Create Next App", // 网站标题description: "Generated by create next app", // 描述信息
};export default function RootLayout({ children }) {return (<html lang="en"><body className={inter.className}>app下面的layout{children}</body></html>);
}
新建app/user/Layout.js存入以下内容
export default function userLayout({ children }) {return (<section>user下面的layout{children}</section>);
}
访问localhost:3000
访问localhost:3000/user
通过对比可以发现,app下面的就是公共的根样式,下面每个Layout.js都会继承到,然后每个文件夹下都可以定义当前路由页面的样式
路由创建
静态路由
在app下面新建demo文件夹,在里面新建page.js和layout.js,内容如下
// page.js
export default function(){return <div>12121</div>
}// layout.js
export default function({children}){return <div>我是demo的母版 <br/>{children}</div>
}
访问:http://localhost:3000/demo
效果图
说明:app下面每个文件夹名称都是一个路由,每个文件夹下面的page.js就是代表当前文件夹的页面,每个文件夹又都有自己的layout.js(layout.js不是必须的,页面内不写这个文件也没关系),里面默认的参数children就是当前页面的元素,也可以说layout.js就相当于当前页面的母版,每个路由都有自己的layout.js但是app下面的layout.js是全局公共的
如果demo下面还有list这个页面,则在demo文件夹内list文件夹,然后在里面创建page.js文件即可,在里面写内容后,页面上面直接访问localhost:3000/demo/list即可
动态路由
当我们访问localhost:3000/demo/list/1或者localhost:3000/demo/list/2这种动态路由怎么实现呢???
这就要用到动态参数了
在app/demo/list下面新建[id]文件夹,这种文件夹名字是[]包裹的就是动态参数了
例如我们的[id]文件夹里面创建page.js内容如下
export default function({params}){return <div>动态参数的值为{params.id}</div>
}
当访问http://localhost:3000/demo/list/2001时,页面效果如下
上面有个弊端就是只支持一级动态参数,如果希望多级的话可以将[id]文件名换成[…id]这样就是可以匹配到后面所有参数,访问localhost:3000/demo/list/2/3/4/5
效果图
路由组
项目下新建三个路径文件
- app/(marketing)/about/page.js
- app/(marketing)/bolg/page.js
- app/(marketing)/(shop)/acconut/page.js
在每个page.js里面随便写点内容,访问以下路径
- localhost:3000/about
- localhost:3000/bolg
- localhost:3000/account
可以发现都能被访问到,总结规律就是文件夹名字带括号的相当于可以忽略了
路由组不参与url的设定的
个人感觉唯一作用是用于设置共同的Layout.js
创建如下两个Layout.js文件
- app/(marketing)/Layout.js
- app/(marketing)/(shop)/Layout.js
在这两个里面添加如下代码
export default function userLayout({ children }) {return (<section>marketing下面的layout{children}</section>);
}
export default function userLayout({ children }) {return (<section>marketing下面shop的layout{children}</section>);
}
运行后会发现,marking的Layout,js被它里面所有文件所共用,shop里面的Layout.js被shop里面的文件所共用,因为这个案例shop在marking里面的,因此shop里面的文件也共用marking里面的样式,这就是路由组,按照上面传统的方式建路由,需要每个文件单独设置自己的Layout.js,使用路由组可以达到复用性
路由跳转和传参以及接收参数
跳转和传参
这里跳转的路径为app/list/[id]/page.js
'use client';
import Link from "next/link";
import { useRouter } from "next/navigation";function Home({ items, time }) {const router = useRouter()return (<div className="Home"><Link href={'/list/1'}>跳转到xiaoji页面</Link><br></br><Link href={'/list/1?name=萧寂'}>跳转到xiaoji页面(带参数)</Link><hr></hr><button onClick={()=>{router.push('/list/1')}}>跳转到xiaoji页面</button><br></br><button onClick={()=>{router.push('/list/1?name=萧寂')}}>跳转到xiaoji页面(第一种带参数)</button><button onClick={()=>{router.push({pathname:'/list/1',query:{name:'萧寂'}})}}>跳转到xiaoji页面(第二种带参数)</button></div>);
}
export default Home;
接收参数
app/list/[id]/page.js里面代码如下
export default async function({params,searchParams}){await new Promise((resolve) => setTimeout(resolve, 2000));return <div>动态参数的值为{params.id},query动态的搜索参数为{searchParams.name}</div>
}
当我在页面输入地址localhost:3000/list/3?name=xiaoji,效果如下:
Loadding加载和流的处理
1.在app下面新建loading.js组件
export default function(){return <div className={"text-2xl text-pink-400"}>Loading...</div>
}
2.修改app/Layout.js
import { Inter } from "next/font/google";
import { Suspense } from "react";
import Loading from './loading'; // 引入app/loading.js
import "./globals.css";const inter = Inter({ subsets: ["latin"] });export const metadata = {title: "Create Next App", // 网站标题description: "Generated by create next app", // 描述信息
};export default function RootLayout({ children }) {return (<html lang="en"><body className={inter.className}><Suspense fallback={<Loading></Loading>}> // 2.使用SusPense将页面包裹app下面的layout{children}</Suspense></body></html>);
}
子组件代码
这里使用了async/await模拟了一下异步,这是个细节,因为上面的loadding效果如果要出来的话,页面数据必须要是有异步效果,因为我没注意到这点,费了点时间才搞明白
export default async function Posts() {await new Promise((resolve) => setTimeout(resolve, 2000));return <div>1111</div>;
}
注意:将Lodding放到app/Layout.js里面包裹的话,则针对所有页面生效,如果某个页面有不一样的loading效果的话,则需要在当前文件夹里面的Layout.js去单独引入对应的loading.js,可以在当前文件夹里面创建个loading.js,这样的话loading.js的样式仅仅作用于当前文件夹下的所有页面
import { Suspense } from "react";
export default function userLayout({ children }) {return (<section>// 这个loading效果仅作用于当前文件夹下面的所有页面<Suspense fallback={<div className={"text-2xl text-pink-400"}>Loading...</div>}>user下面的layout{children}</Suspense></section>);
}
注意:必须是渲染的页面内有异步操作(如async/await)才会有Loading.js效果
错误处理
新建app/error.js,放入以下内容
'use client'export default function({error,reset}){return (<div><h2>我是全局的错误样式处理</h2><button onClick={()=>reset()}>重试一下</button></div>)
}
也可以对每个页面单独定义路由样式,只需要在目标页面的文件夹内新建error.js,放入以下内容即可
例如我在app/user/error.js内加入以下内容
'use client'export default function({error,reset}){return (<div><h2>app/user 页面内有错误啦!!!</h2><button onClick={()=>reset()}>重试一下</button></div>)
}
例如我们在目标的user页面加入一些错误信息
export default function Posts() {console.log('a',a); // 这里没有a变量,因此这里会报错return <div>1111</div>;
}
当我们在浏览器访问localhost:3000/user就会报出以下错误
当我们访问其他页面有错误信息时,但是没有给那个页面单独定义错误样式,则会触发全局的错误样式
例如访问: localhost:3000/about
链接和导航
修改下app/page.js内容如下
'use client';
import Link from "next/link";
import { useRouter } from "next/navigation";export default function Home() {const router = useRouter()return (<><h1 className="text-4xl text-orange-600">Hello Name</h1><br></br><Link href={"/user"}>跳转到user路由</Link><br></br><button onClick={()=>{router.push('/user')}}>点击跳转/user</button></>);
}
滚动到新路由的指定位置处,相当于锚点链接
<Link href="/dashboard#settings">Settings</Link>// Output
<a href="/dashboard#settings">Settings</a>
平行路由(Parallel Routes)
在app下面新建@home和@setting文件夹,里面都新建一个page.js文件,在里面写一点页面
在app/Layout.js里面改为如下页面代码
import { Inter } from "next/font/google";
import { Suspense } from "react";
import Loading from './loading';
import "./globals.css";const inter = Inter({ subsets: ["latin"] });export const metadata = {title: "Create Next App", // 网站标题description: "Generated by create next app", // 描述信息
};export default function RootLayout({ children,home,setting }) {return (<html lang="en"><body className={inter.className}><Suspense fallback={<Loading></Loading>}>app下面的layout{home}{children}{setting}</Suspense></body></html>);
}
可以发现组件效果已经出来了
这里有个注意点,使用了平行路由后,这个文件夹内不要创建别的路由文件夹了,因为就算创建了后面的路径也会报错一堆404,我不知道是正常情况还是异常情况,本人就这样理解的,因此把所有的需要用到平行路由的界面我都归类为最终页面了
组件化渲染
下面是可以应用到我们页面里面的组件的案例
在app平级处创建components/frame/index.js,放入以下内容
import Image from "next/image";export default function({photo}){console.log('photo',photo);return <><Image src={photo.src} alt="" width={600} height={600} className={'w-full object-cover aspect-square col-span-2 w-28'}></Image></>
}
在app里面新建photo/page.js文件,插入以下内容
import Photo from "@/components/frame" // 引入组件
export default function(){const photo = {src:'https://take-saas.oss-cn-hangzhou.aliyuncs.com/wechat_applets/coach/bgcimg/bgc-13.png'}// 给组件传值return <Photo photo={photo}></Photo>
}
注意:这里可能会报错图片问题(网络图片需要加一下白名单才能正常加载,如下在next.config.mjs里面进行配置)
/** @type {import('next').NextConfig} */
const nextConfig = {images:{domains:['take-saas.oss-cn-hangzhou.aliyuncs.com'] // 这里是存放域名白名单处}
};export default nextConfig;
然后就可以看到图片正常加载了
定义404页面
在app下面新建not-found.js,放入以下内容
export default function(){return <div className={"text-2xl text-pink-400"}>访问页面不存在...</div>
}
当页面访问一个不存在的页面路由时,页面显示效果如下
自定义页面网站标题(有利于SEO)
静态设置meta标签
在任意page.js内都按照下面这样写就行
export const metadata = {title: "我是list页面", // 页面标题description: "list页面描述", // 页面描述keywords:"list页面,nextjs开发,测试页面" // 关键词};
export default function(){return <div>list</div>
}
只要在页面内部导出metadata 即可,里面写好网站title和描述信息,这是一种约束,nextjs默认你导出这个就是设置title和描述的
效果图
动态设置meta标签
例如我在app/list/[id]/page.js加入以下代码
export async function generateMetadata({params,searchParams}){// 这个方法是异步方法return {title:`这是动态参数:${params.id}-${searchParams.name}`, // 这个id其实就是动态路由的动态参数,跟下面的页面接收到的params值一样}}export default async function({params,searchParams}){await new Promise((resolve) => setTimeout(resolve, 2000));return <div>动态参数的值为{params.id},query动态的搜索参数为{searchParams.name}</div>
}
在页面输入地址localhost:3000/list/3?name=xiaoji,效果如下:
编写Api接口
静态路径
在app下面新建api文件夹,在里面新建goods文件夹在里面再次新建route.js文件,放入以下内容
主意api文件夹一定是要放到app文件夹下面的,并且接口文件都是route.js命名跟page.js一样是约定名称,固定的
import { NextRequest,NextResponse } from "next/server";export const GET = ()=>{return NextResponse.json({succes:true,errorMessage:"获取数据",data:{}})
}
重启项目访问http://localhost:3000/api/goods,效果如下
动态路径
在app下面新建api文件夹,在里面新建goods文件夹,再新建[id]文件夹,在里面再次新建route.js文件,放入以下内容
import { NextRequest,NextResponse } from "next/server";export const GET = (req,{params})=>{return NextResponse.json({succes:true,errorMessage:"获取单条记录"+params.id,data:{}})
}
浏览器访问:http://localhost:3000/api/goods/123
发送接口请求
注意:在app文件夹下面所有文件夹名字前面带_的都不会被自动解析为路由
- 在app/list下面新建_components作为组件文件夹,在里面新建list.js写客户端组件进行发请求,代码如下:
"use client"
import { useEffect,useState } from "react"
export default function(){const [data,setData] = useState([]) useEffect(()=>{fetch("api/goods").then((res)=>res.json()).then((res)=>{setData(res.data)})},[])return <div><ul>{data.map((item,index)=>{return <li key={item.id}>{item.name}</li>})}</ul></div>
}
- 在app/list/page.js里面引入组件
import List from "./_components/list";export default function(){return <List></List>
}
- 访问http://localhost:3000/list,效果图如下
数据库引入
在前端使用这个用于操作数据库的库https://www.prisma.io/
1.安装库
yarn add prisma --save-dev
// 下面这个安装官网没有,但是我报了一个错误是因为没有这个模块导致的,如果跟我一样报错的话就手动安装一下
yarn add @prisma/client
2.初始化数据库(sqlite数据库)
npx prisma init --datasource-provider sqlite
3.在schema.prisma文件内新增一个model模型,也就是表
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schemagenerator client {provider = "prisma-client-js"
}datasource db {provider = "sqlite"url = env("DATABASE_URL")
}// 新增如下
model Goods{id String @id @unique @default(uuid())name Stringdesc String @default("")content String @default("") createAt DateTime @default(now()) @map("create_at") // @map起别名,默认当前时间updateAt DateTime @updatedAt @map("update_at")@@map("products") // 表名
}
4.生成数据库(项目下终端执行命令)
npx prisma db push
5.这时候就会看到prisma下面多了一个dev.db数据库文件了
6.使用数据库软件navicat打开这个数据库就可以发现刚刚我们新建的表
7.连接数据库(在prisma官网搜Solution这个关键词,下面这段代码即可,也可以直接复制我的也是一样的)
app同级位置新建文件db.js放入以下内容
import { PrismaClient } from '@prisma/client'const prismaClientSingleton = () => {return new PrismaClient()
}const prisma = globalThis.prismaGlobal ?? prismaClientSingleton()export default prismaif (process.env.NODE_ENV !== 'production') globalThis.prismaGlobal = prisma
8.将刚刚的/api/good/route.js文件做修改,做两个接口,新增和修改,代码如下
import { NextRequest,NextResponse } from "next/server";
import prisma from '@/db'
export const GET = async ()=>{// 查询数据,根据时间倒序排序// 创建的模型名称小写的(goods)const data =await prisma.goods.findMany({orderBy:{createAt:"desc",}})return NextResponse.json({succes:true,successMessage:"获取数据成功",data})
}// 新增数据
export const POST = async (req)=>{const data = await req.json() // 获取请求体中传递的json数据await prisma.goods.create({data,})return NextResponse.json({succes:true,successMessage:"创建数据成功",data:{}})
}
9:使用apiFox等工具添加数据(post请求,端口号3000)
接口地址为:http:localhost:3000/api/goods
参数:点击body->json->输入{name:‘萧寂’}
发请求:点击send
10:数据创建成功后刷新下数据库,使用数据库软件查看数据
11:在浏览器访问上面发送接口请求的那个页面,看看是否显示了数据
访问:http:localhost:3000/list
可以发现,数据确实被加进来了,至此添加和查询数据的接口准备完毕
项目阶段(做个管理后台)
引入Antd组件库
官方网站
安装
yarn add antd
随便找个页面放入antd组件查看页面是否有效果,我这里在app/page.js放入以下内容
import React from 'react';
import { DatePicker } from 'antd';const App = () => {return <DatePicker />;
};export default App;
浏览器访问:http://localhost:3000/
效果图
这样就代表组件库已经引入进来了
但是如果发现样式和antd样式不一致,就是tailwindcss和其样式冲突了,我们需要在tailwind.config.js进行配置
/** @type {import('tailwindcss').Config} */
module.exports = {content: ["./pages/**/*.{js,ts,jsx,tsx,mdx}","./components/**/*.{js,ts,jsx,tsx,mdx}","./app/**/*.{js,ts,jsx,tsx,mdx}",],theme: {extend: {backgroundImage: {"gradient-radial": "radial-gradient(var(--tw-gradient-stops))","gradient-conic":"conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",},},},plugins: [],corePlugins:{preflight:false // 新增,页面就正常了}
};
项目结构搭建和配置
在app下面新建admin文件夹
在admin下面新建_components/AntdAdmin.js组件作为管理系统主页面容器,内容如下(这个后台管理布局直接从antd组件库的layout直接复制粘贴来的)
"use client";
import {Button, Layout, Menu, theme } from "antd";
import "antd/dist/reset.css";
import {MenuFoldOutlined,MenuUnfoldOutlined,UploadOutlined,UserOutlined,VideoCameraOutlined,
} from "@ant-design/icons";
import { useState } from "react";
const { Header, Sider, Content } = Layout;
export default function ({ children }) {const [collapsed, setCollapsed] = useState(false);const {token: { colorBgContainer, borderRadiusLG },} = theme.useToken();return (// 设置语言包<><Layout style={{height:'100vh'}}><Sider trigger={null} collapsible collapsed
相关文章:

使用Nextjs学习(学习+项目完整版本)
创建项目 运行如下命令 npx create-next-app next-create创建项目中出现的各种提示直接走默认的就行,一直回车就行了 创建完成后进入到项目运行localhost:3000访问页面,如果和我下面页面一样就是创建项目成功了 整理项目 将app/globals.css里面的样式都删除,只留下最上面三…...

KUKA机器人KRC5控制柜面板LED显示
对于KUKA机器人新系列控制柜KRC5控制柜来说,其控制柜面板LED布局如下图: 其中①②③④分别为: 1、机器人控制柜处于不同状态时,LED显示如下: 2、机器人控制柜正在运行时: 3、机器人控制柜运行时出现的故障…...
为什么选择Python作为AI开发语言
为什么Python适合AI 在当前的科技浪潮中,人工智能(AI)无疑是最热门的话题之一。无论是自动驾驶、智能推荐还是自然语言处理,AI都在不断改变我们的生活。而在这场技术革命中,Python作为主要的编程语言之一,…...

【算法篇】求最长公共前缀JavaScript版本
题目描述 给你一个大小为 n 的字符串数组 strs ,其中包含n个字符串 , 编写一个函数来查找字符串数组中的最长公共前缀,返回这个公共前缀。 数据范围: 数据范围:0<n<5000,0<len(strsi)< 5000 进阶:空间复杂度 O(1)&a…...

搭建RocketMQ主从异步集群
搭建RocketMQ主从异步集群 1、RocketMQ集群模式 为了追求更好的性能,RocketMQ的最佳实践方式都是在集群模式下完成的。RocketMQ官方提供了三种集群搭建方式: 2主2从异步通信方式:使用异步方式进行主从之间的数据复制。吞吐量大,…...
最大子段和问题
最大子段和问题 分数 15 全屏浏览 切换布局 作者 王东 单位 贵州师范学院 最大子段和问题。给定由n个整数组成的序列,求序列中子段的最大和,若所有整数均为负整数时定义最大子段和为0。 输入格式: 第一行输入整数个数n(1≤n≤1000&…...

Vue3中的常见组件通信之mitt
Vue3中的常见组件通信之mitt 概述 在vue3中常见的组件通信有props、mitt、v-model、 r e f s 、 refs、 refs、parent、provide、inject、pinia、slot等。不同的组件关系用不同的传递方式。常见的撘配形式如下表所示。 组件关系传递方式父传子1. props2. v-model3. $refs…...

MySQL快速入门(极简)
SQL 介绍及 MySQL 安装 一、实验简介 本课程为实验楼提供的 MySQL 实验教程,所有的步骤都在实验楼在线实验环境中完成,学习中请按照实验步骤依次操作。 本课程为 SQL 基本语法及 MySQL 基本操作的实验,理论内容较少,动手实践多…...
CentOS7安装NVIDIA显卡驱动指引【笔记】
CentOS7安装NVIDIA显卡驱动指引【笔记】 实践设备:华硕FX-PRO(NVIDIA GeForce GTX 960M) 环境准备: 1、将系统安装到设备上正常运行; 2、设备网络调试,可以正常访问外网; 3、配置ssh服务(非必要,根据实际情况)。 说明: 本文档所提供的指引和参考主要基于特定实践…...

【RabbitMQ】RabbitMQ配置与交换机学习
【RabbitMQ】RabbitMQ配置与交换机学习 文章目录 【RabbitMQ】RabbitMQ配置与交换机学习简介安装和部署1. 安装RabbitMQ2.创建virtual-host3. 添加依赖4.修改配置文件 WorkQueues模型1.编写消息发送测试类2.编写消息接收(监听)类3. 实现能者多劳 交换机F…...
常见排序算法,快排,希尔,归并,堆排
后面的排序中都要用到的函数 //交换 void Swap(int* p1, int* p2) {int* tmp *p1;*p1 *p2;*p2 tmp; } 包含的头文件 "Sort.h" #pragma once #include<stdio.h> #include<stdlib.h> #include<assert.h> #include<time.h> #include<s…...
语法的时态1——一般现在时(1)
定义:一般现在时用来表示经常发生的动作,以及客观事实。 一般现在时的构成以及标志词 1.一般现在时的结构 (1)主系表结构 构成:主语be(am,is,ear)其他。属于状态句。 I…...

JAVA:在IDEA引入本地jar包的方法并解决打包scope为system时发布无法打包进lib的方案
一.引入本地Jar包的步骤 有时maven依耐的包是本地的jar包,此时需要进行以下步骤设置。 步骤1.在pom.xml中添加插件设置,将system范围包含进来,此设置是为了在打包时,本地jar包自动生成到部署包里。(若无法打进包,请参考下文的方…...

Hadoop3:MapReduce源码解读之Map阶段的CombineFileInputFormat切片机制(4)
Job那块的断点代码截图省略,直接进入切片逻辑 参考:Hadoop3:MapReduce源码解读之Map阶段的Job任务提交流程(1) 6、CombineFileInputFormat原理解析 类的继承关系 与TextInputFormat切片机制的区别 框架默认的TextI…...
GPT-4o:OpenAI的最新篇章与深度探索
引言: 在人工智能领域,自然语言处理(NLP)技术持续引领着技术创新的步伐。自2023年引入以来,GPT系列模型一直以其卓越的语言生成能力而闻名,近期的迭代——GPT-4o,更是为这一领域的研究和应用带…...

OpenGauss数据库-5.数据更新
第1关:插入数据 gsql -d postgres -U gaussdb -W "passwd123123" create table student (id integer primary key,name char(20),age integer ); insert into student values(1,"lily",20),(2,lily,21),(3,marry,19); 第2关:删除数…...
【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 机场航班调度程序(100分) - 三语言AC题解(Python/Java/Cpp)
🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 📎在线评测链接 🌍 评测功能需要订阅专栏后私信联系清隆解锁~ 文章目录 …...

Spark作业运行异常慢的问题定位和分析思路
一直很慢 🐢 运行中状态、卡住了,可以从以下两种方式入手: 如果 Spark UI 上,有正在运行的 Job/Stage/Task,看 Executor 相关信息就好。💻 第一步,如果发现卡住了,直接找到对应的…...

音视频转为文字SuperVoiceToText
音视频转为文字SuperVoiceToText,它能够把视频或语音文件高效地转换为文字,它是基于最为先进的 AI 大模型,通过在海量语音资料上进行训练学习而造就,具备极为卓越的识别准确率。 不仅如此,它支持包括汉语、英语、日语…...

Python基础教程(九):Lambda 函数
💝💝💝首先,欢迎各位来到我的博客,很高兴能够在这里和您见面!希望您在这里不仅可以有所收获,同时也能感受到一份轻松欢乐的氛围,祝你生活愉快! 💝Ὁ…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...

Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...

CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...

论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...