当前位置: 首页 > news >正文

Vue3+Vant开发:登录功能

🙈作者简介:练习时长两年半的Java up主
🙉个人主页:程序员老茶
🙊 ps:点赞👍是免费的,却可以让写博客的作者开心好久好久😎
📚系列专栏:Java全栈,计算机系列(火速更新中)
💭 格言:种一棵树最好的时间是十年前,其次是现在
🏡动动小手,点个关注不迷路,感谢宝子们一键三连

目录

  • 课程名:Vue 3
    • 内容/作用:知识点/设计/实验/作业/练习
    • 学习:Vue3+Vant开发:登录功能
    • 1、创建登录路由
    • 2、实现登录布局结构
    • 3、登录布局实现
    • 4、实现基本登录功能
    • 5、登录状态提示
    • 6、表单验证功能
    • 7、处理用户Token
    • 8、封装本地存储操作
    • 总结

课程名:Vue 3

内容/作用:知识点/设计/实验/作业/练习

学习:Vue3+Vant开发:登录功能

1、创建登录路由

npm install vue-router@4

以上安装了最新版本的vue-router.

下面在src目录下面创建router目录,在该目录下面创建index.js文件,在该文件中完成路由的配置

index.js文件中代码如下所示:()

在下面的代码中,首先从vue-router中导入createRouter以及createWebHashHistory.

createRouter用来创建路由实例

createWebHashHistory创建hash路由

Layout组件用来完成整个后台管理页面的布局。

routes数组中,定义了相应的路由规则

import { createRouter, createWebHashHistory } from "vue-router";
const routes = [{path: "/login",name: "login",component: () => import("../views/login/index.vue"),},
];
//创建路由实例
const router = createRouter({//history模式:createWebHistoryhistory: createWebHashHistory(), //使用hash模式routes,
});
export default router;

下面在src目录下面创建views目录,在该目录下面创建login目录,然后在创建index.vue.

该组件中的内容如下所示:

<template><div>登录</div>
</template><script>
export default {};
</script><style></style>

下面,返回到main.js文件中使用创建好的路由对象

import { createApp } from "vue";
import App from "./App.vue";
import Vant from "vant";
import "vant/lib/index.css";
import "amfe-flexible";
import router from "./router"; //导入路由对象
createApp(App).use(Vant).use(router).mount("#app"); //使用路由

同时在App.vue文件中,添加router-view,指定路由的出口。

<template><router-view></router-view>
</template><script setup></script><style></style>

在浏览器中输入http://localhost:3000/#/login查看效果。

2、实现登录布局结构

<template><div class="login-container"><!-- 导航栏 --><van-nav-bar title="登录" /><!-- 导航栏结束 --><!-- 登录表单 --><van-form><van-field name="userName" placeholder="请输入用户名" /><van-field name="userPwd" placeholder="请输入密码" /><div style="margin: 16px"><van-button block type="primary" native-type="submit">提交</van-button></div></van-form><!-- 登录表单结束 --></div>
</template><script>
export default {};
</script><style></style>

3、登录布局实现

这里我们首先设置一下,导航栏的样式。由于很多页面都会用到导航栏,所以可以将样式定义在全局的文件中,而不是单独的定义在登录组件中。

src目录下面创建styles目录,在该目录下面创建index.css文件,该文件中的代码如下所示:

.page-nav-bar {background-color: #3296fa;
}
.page-nav-bar .van-nav-bar__title {/* 这里的van-nav-bar__title,可以查看原有的导航栏的样式*/color: #fff;
}

在登录组件的导航栏中使用该样式。(在main.js文件中导入import "./styles/index.css";

  <van-nav-bar title="登录" class="page-nav-bar" />

下面给登录表单的文本框与密码框添加对应的图标。

对应的官网:

https://vant-contrib.gitee.io/vant/v3/#/zh-CN/field
 <van-form><van-field name="userName" placeholder="请输入用户名" left-icon="manager" /><van-field name="userPwd" placeholder="请输入密码"   left-icon="lock"/></van-field><div style="margin: 16px"><van-button block type="primary" native-type="submit"> 提交</van-button></div></van-form>

这里给手机号与验证码添加了left-icon设置了图标。同时设置了“发送验证码”的按钮

4、实现基本登录功能

注意:这里只是实现基本登录效果,把服务端返回的内容打印出来,不涉及到登录状态的提示与登录状态的存储操作。

首先在src目录下面创建api目录,在该目录下面创建user.js文件,该文件中封装了用户请求的相关处理模块。

// 封装用户相关的请求模块
import request from "../utils/request";
export const login = (data) => {return request({method: "POST",url: "/user/login",data,});
};

下面修改login.vue组件中的内容

  <div class="login-container"><!-- 导航栏 --><van-nav-bar title="登录" class="page-nav-bar" /><!-- 导航栏结束 --><!-- 登录表单 --><van-form @submit="onSubmit"><van-fieldname="userName"placeholder="请输入用户名"v-model="userName"left-icon="manager":rules="userFormRules.userName"/><van-fieldname="userPwd"placeholder="请输入密码"v-model="userPwd"left-icon="lock":rules="userFormRules.userPwd"></van-field><div style="margin: 16px"><van-button block type="primary" native-type="submit">登录</van-button></div></van-form><!-- 登录表单结束 --></div>

给每个van-field绑定了v-model,同时给van-form添加了@submit事件。

<script>
import { reactive, toRefs } from "vue";
import { login } from "../../api/user"; //导入login方法,进行请求的发送function useSubmit(user) {
const onSubmit = async () => {//1、获取表单数据//2、表单验证//3、提交表单请求Toast.loading({message: "登录中...",forbidClick: true, //禁用背景点击duration: 0, //持续时间,默认是2000毫秒,如果为0则持续展示});const res = await login(user);if (res.data.code === 0) {store.commit("setUser", res.data);Toast.success("用户登录成功");} else {Toast.fail("用户名或密码错误");}//4、根据请求响应结果处理后续操作。};return {onSubmit,};
}
export default {setup() {const user = reactive({userName: "", //用户名userPwd: "", //用户密码});return {...toRefs(user),...useSubmit(user),};},
};
</script>

setup方法中,定义user响应式对象,最后返回。同时将外部定义的useSubmit方法进行调用。

5、登录状态提示

const onSubmit = async () => {//1、获取表单数据//2、表单验证//3、提交表单请求Toast.loading({message: "登录中...",forbidClick: true, //禁用背景点击duration: 0, //持续时间,默认是2000毫秒,如果为0则持续展示});const res = await login(user);if (res.data.code === 0) {store.commit("setUser", res.data);Toast.success("用户登录成功");} else {Toast.fail("用户名或密码错误");}//4、根据请求响应结果处理后续操作。};return {onSubmit,};
}

这里使用了Toast组件,同时需要进行导入:

import { Toast } from "vant";

由于网络比较快,可能看不到登录中...这个提示,所以可以把网络设置慢一些。

可以修改NetWork中的No throttling中的Slow 3G

6、表单验证功能

setup函数中定义校验规则,并且将其返回。

setup() {const user = reactive({userName: "", //用户名userPwd: "", //用户密码});//定义校验规则const userFormRules = {userName: [{ required: true, message: "请填写用户名" }],userPwd: [{required: true,message: "请填写密码",},{pattern: /^\d{6}$/,message: "密码格式错误",},],};return {...toRefs(user),...useSubmit(user),userFormRules, //返回校验规则};},

在表单中使用校验规则:

     <van-fieldname="userName"placeholder="请输入用户名"v-model="userName"left-icon="manager":rules="userFormRules.userName"/><van-fieldname="userPwd"placeholder="请输入密码"v-model="userPwd"left-icon="lock":rules="userFormRules.userPwd"></van-field>

7、处理用户Token

用户登录成功以后,会返回token数据。

Token是用户登录成功之后服务端返回的一个身份令牌,在项目中经常要使用。

例如:访问需要授权的API接口。

校验页面的访问权限等。

同时,这里我们还需要将token数据进行存储,这样在访问其它的页面组件的时候,就可以获取token数据来进行校验。

关于token数据存储在哪儿呢?

可以存储到本地:

存储到本地的问题是,数据不是响应式的。

存储到Vuex中,获取方便,并且是响应式的。但是存储到Vuex中也是有一定的问题的,就是当我们刷新浏览器的时候,数据就会丢失,所以还是需要把token数据存放到本地,存储到本地的目的就是为了进行持久化。

所以这里我们需要在登录成功以后,把token数据存储到vuex中,这样可以实现响应式,在本地存储就是为了解决持久化的问题。

安装最新版本的Vuex

npm install vuex@next --save

下面在src目录下面创建store目录,在store目录中index.js文件,该文件中的代码如下所示:

import { createStore } from "vuex";
const store = createStore({state: {//存储当前登录用户信息,包含token等数据user: null,},mutations: {setUser(state, data) {state.user = data;},},
});
export default store;

在上面的代码中,创建了store容器,同时指定了state对象,在该对象中定义user属性存储登录用户信息。

mutations中定义setUser方法,完成用户信息的更新。

下面,要实现的就是,当登录成功以后,更新user这个状态属性。

当然,这里首先要做的就是把store注入到Vue的实例中。

import { createApp } from "vue";
import App from "./App.vue";
import Vant from "vant";
import "vant/lib/index.css";
import "amfe-flexible";
import "./styles/index.css";
import router from "./router";
import store from "./store"; //导入store
createApp(App).use(Vant).use(router).use(store).mount("#app"); //完成store的注册操作

main.js文件中,我们导入了store,并且注册到了Vue实例中。

下面返回到views/login/index.vue页面中,把登录的信息存储到store容器中。

import { reactive, toRefs, ref } from "vue";
import { login, sendSms } from "../../api/user";
import { Toast } from "vant";
import { useStore } from "vuex"; //导入useStore

在上面的代码中导入useStore.

export default {setup() {const loginForm = ref();//获取storeconst store = useStore();

setup函数中,调用useStore方法,获取store容器。

 return {...toRefs(user),...useSubmit(user, store),//在调用useSubmit方法的时候传递store容器userFormRules,loginForm,};
//用户登录
function useSubmit(user, store) {const onSubmit = async () => {//1、获取表单数据//2、表单验证//3、提交表单请求Toast.loading({message: "登录中...",forbidClick: true, //禁用背景点击duration: 0, //持续时间,默认是2000毫秒,如果为0则持续展示});const res = await login(user);if (res.data.code === 0) {store.commit("setUser", res.data);Toast.success("用户登录成功");} else {Toast.fail("用户名或密码错误");}//4、根据请求响应结果处理后续操作。};return {onSubmit,};
}

登录成功以后,获取到返回的数据,同时调用store中的commit方法完成数据的保存

现在,我们虽然把登录成功的数据,存储到Vuex中,但是当我们刷新浏览器的时候,Vuex中的数据还是会丢失的。所以这里,我们还需要将其存储到本地中。

下面修改一下store/index.js文件中的代码:

import { createStore } from "vuex";
const TOKEN_KEY = "TOUTIAO_USER";
const store = createStore({state: {//存储当前登录用户信息,包含token等数据// user: null,user: JSON.parse(window.localStorage.getItem(TOKEN_KEY)),},mutations: {setUser(state, data) {state.user = data;window.localStorage.setItem(TOKEN_KEY, JSON.stringify(state.user));},},
});
export default store;

mutations中的setUser方法中,将登录成功的用户数据存储到了localStorage中,在存储的时候,将数据转成了字符串。

同时在state中获取数据的时候,就从localStorage中获取,当然获取的时候,再将其转换成对象的形式。

下面,我们可以在App.vue中做一下测试:

<template><div><router-view></router-view></div>
</template><script>
import { useStore } from "vuex";
export default {setup() {const store = useStore();console.log(store.state.user);},
};
</script><style></style>

通过查看浏览器的控制台,可以查看到对应的登录用户的token数据

8、封装本地存储操作

在我们的项目中,有很多的地方都需要获取本地存储的数据,如果每次都写:

JSON.parse(window.localStorage.getItem(TOKEN_KEY)),
window.localStorage.setItem(TOKEN_KEY, JSON.stringify(state.user));

就比较麻烦了。所以这里我们建议把操作本地数据单独的封装到一个模块中。

utils目录下面创建storage.js文件,该文件中的代码如下所示:

// 存储数据
export const setItem = (key, value) => {//将数组,对象类型的数据转换为JSON格式的字符串进行存储if (typeof value === "object") {value = JSON.stringify(value);}window.localStorage.setItem(key, value);
};
//获取数据
export const getItem = (key) => {const data = window.localStorage.getItem(key);//这里使用try..catch的,而不是通过if判断一下是否为json格式的字符串,然后在通过parse进行转换呢,目的就是是为了方便处理,因为对字符串进行判断看一下是否为json格式的字符串,比较麻烦一些。还需要通过正则表达式来完成。而通过try..catch比较方便// 如果data不是一个有效的json格式字符串,JSON.parse就会出错。try {return JSON.parse(data);} catch (e) {return data;}
};
//删除数据
export const removeItem = (key) => {window.localStorage.removeItem(key);

下面返回到store/index.js文件中,修改对应的代码,这里使用我们上面封装好的代码。

import { createStore } from "vuex";
import { getItem, setItem } from "../utils/storage";
const TOKEN_KEY = "TOUTIAO_USER";
const store = createStore({state: {//存储当前登录用户信息,包含token等数据// user: null,// user: JSON.parse(window.localStorage.getItem(TOKEN_KEY)),user: getItem(TOKEN_KEY),},mutations: {setUser(state, data) {state.user = data;setItem(TOKEN_KEY, state.user);// window.localStorage.setItem(TOKEN_KEY, JSON.stringify(state.user));},},
});
export default store;

在上面的代码中,我们导入getItemsetItem两个方法,然后在存储登录用户信息,和获取登录用户信息的时候,直接使用这两个方法,这样就非常简单了。

下面返回浏览器进行测试。

把以前localStorage中存储的内容删除掉。

然后重新输入用户名和密码,发现对应的localStorage中存储了对应的数据。

总结

感谢小伙伴们一键三连,咱们下期文章再见~

往期专栏
Java全栈开发
数据结构与算法
计算机组成原理
操作系统
数据库系统
物联网控制原理与技术

相关文章:

Vue3+Vant开发:登录功能

&#x1f648;作者简介&#xff1a;练习时长两年半的Java up主 &#x1f649;个人主页&#xff1a;程序员老茶 &#x1f64a; ps:点赞&#x1f44d;是免费的&#xff0c;却可以让写博客的作者开心好久好久&#x1f60e; &#x1f4da;系列专栏&#xff1a;Java全栈&#xff0c;…...

Linux程序调试优化(1)——内存占用详解及优化思路

文章目录 1.free查看总体的内存占用2./proc/$PID/status 查看某进程状态 linux开发最重要的两个参数&#xff0c;分别是内存以及CPU使用率&#xff0c;若内存出现严重不足&#xff0c;则在需要使用内存时&#xff0c;可能出现申请不到的情况&#xff0c;导致 OOM&#xff0c;L…...

高效解决Visual Studio Code中文乱码问题

文章目录 问题解决步骤 问题 Visual Studio Code新建一个文件编码方式总是默认GBK&#xff0c;如果我不修改成默认UTF-8&#xff0c;那么每次运行&#xff0c;如果有中文需要输出就会乱码&#xff01; 解决步骤 之后我会持续更新&#xff0c;如果喜欢我的文章&#xff0c;请记…...

springboot接口提高查询速度方法

接口想要提高查询速度&#xff0c;需要减少查询数据库的次数&#xff0c;需要把循环里面的查询提出来一次性查询完毕&#xff0c;然后通过java代码来获取响应的值。如下所示&#xff1a; List<OrderInfoHtVO> orderInfoList orderInfoService.getOrderInfoHtlist(query…...

如何在苹果手机上安装iOS应用的.ipa文件?

哈喽&#xff0c;大家好呀&#xff0c;淼淼又来和大家见面啦&#xff0c;如今移动应用市场不断的发展&#xff0c;许多开发者小伙伴们都选择将他们的应用发布到苹果App Store上&#xff0c;但是&#xff0c;有时候他们可能希望通过直接分享IPA文件来分发他们的App&#xff0c;那…...

IDEA pom.xml显示灰色并被划线

在使用 IDEA 进行开发的过程中&#xff0c;有时候会遇到 pom.xml 显示灰色并被划线的情况&#xff0c;如下图&#xff1a; 这一般是因为该文件被 Maven 忽略导致的&#xff0c;可以进行如下操作恢复&#xff1a; 设置保存后&#xff0c;可以看到 pom.xml 恢复了正常&#xff1a…...

玄子Share-使用 Pycharm 执行 Shell 脚本

玄子Share-使用 Pycharm 执行 Shell 脚本 Why&#xff1f; 为什么我要使用 Pycharm 执行 Shell 脚本呢&#xff0c;我直接使用 Linux 不行吗&#xff1f; 使用 Pycharm 执行 Shell 脚本的好处 我们的宿主机都是 WIndows 平台&#xff0c;若想编译 Shell 脚本&#xff0c;我…...

如何让Nrf connect、EFR connect直接显示特征值数据及其单位

效果如图&#xff1a;app直接显示了我的温度&#xff0c;并且有两位小数&#xff0c;还有温度单位。这是怎么做到的呢&#xff1f; 这次我们仍以TLS8258为例&#xff0c;当然如果是其他蓝牙芯片&#xff0c;配置方式也是大差不差&#xff0c;规则一样的。 #define GATT_CHARA…...

python笔记

Vim 修改文件格式 unix|dos vim fileName :set ff //显示出文件格式类型 :set ffunix //设置成unix格式 :set ffdos //windows文件格式python *和**的区别 将可变关键字打包成不可变的元组 def func(*args): print(args) func(1, 2, 3) # 输出&#xff1a;(1, 2, 3)…...

Java编译期注解处理器AbstractProcessor使用

我们接触的注解主要分为以下两类 运行时注解&#xff1a;通过反射在运行时动态处理注解的逻辑编译时注解&#xff1a;通过注解处理器在编译期动态处理相关逻辑 编译期注解我们常用的有Lombok&#xff0c;在class文件中自动生成get和set方法 解编译期处理流程最关键的一个类就…...

JetBrains相关的IDE有哪些?

JetBrains是一家成立于2002年的捷克软件开发公司&#xff0c;总部位于捷克的布拉格&#xff0c;同时在俄罗斯的圣彼得堡及美国麻州波士顿等地设有办公室。该公司以其高质量的集成开发环境&#xff08;IDE&#xff09;产品而闻名&#xff0c;这些产品被广泛应用于各种编程语言和…...

Git-常规用法-含解决分支版本冲突解决方法

目录 前置条件 已经创建了Gitee账号 创建一个远程仓库 Git的优点 版本控制 Git 下载 Git的使用 检查Git的是否安装成功 git的常用命令 常用流程 Git 分支 分支流程 Git 远程仓库 远程仓库流程 特殊 可能遇到的问题 前置条件 已经创建了Gitee账号 创建一个远程仓…...

基于springboot实现大型商场应急预案管理系统项目【项目源码+论文说明】

基于SpringBoot实现大型商场应急预案管理系统演示 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了大型商场应急预案管理系统的开发全过程。通过分析大型商场应急预案管理系统管理的不足&#xff0c;创建了一个…...

系统学c#:1、基础准备(软件下载与安装)

一、Vs软件下载与安装 访问Visual Studio官方网站&#xff1a; https://visualstudio.microsoft.com/zh-hans/downloads 下载Visual Studio 运行exe文件&#xff0c;点击“继续” 初始文件安装完成后选择我们需要安装的项&#xff0c;并勾选好必要的单个组件&#xff0c;设…...

解决CSS中鼠标移入到某个元素其子元素被遮挡的问题

我们在开发中经常遇到一种场景&#xff0c;就是给元素加提示信息&#xff0c;就是鼠标移入到盒子上面时&#xff0c;会出现提示信息这一功能&#xff0c;如果我们给盒子加了hover&#xff0c;当鼠标移入到盒子上时&#xff0c;让他往上移动5px&#xff0c;即transform: transla…...

【华为OD机试】虚拟理财游戏【C卷|100分】

【华为OD机试】-真题 !!点这里!! 【华为OD机试】真题考点分类 !!点这里 !! 题目描述 在一款虚拟游戏中生活,你必须进行投资以增强在虚拟游戏中的资产以免被淘汰出局。 现有一家Bank,它提供有若干理财产品 m 个,风险及投资回报不同,你有 N(元)进行投资,能接收的总风险…...

ssh 使用

ssh 使用 一、ssh 安装二、ssh 使用1. ssh 登录2. ssh-keygen 免密登录(1) ssh 生成密钥(2) 开启远程主机的密钥登陆(3) ssh 分发公钥 3. ssh-copy-id 复制公钥到远程主机4. scp 复制 系统环境: linux(ubuntu,debian,kali) 一、ssh 安装 sudo apt update sudo apt install op…...

Springboot+Vue项目-基于Java+MySQL的母婴商城系统(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…...

Android多线程:Handler runOnUiThread 异步消息处理机制

目录 一&#xff0c;Android中的多线程问题 1.模拟耗时工作 2.Android开启子线程 二&#xff0c;在子线程中更新UI 1.异步消息处理机制 Handler 2.使用runOnUiThread更新UI 一&#xff0c;Android中的多线程问题 Android用户界面是与用户交互的接口&#xff0c;对于用户的…...

AndroidStudio 导出aar包,并使用

打包 1、确认当前选项是否勾选&#xff0c;如未勾选请先勾选。 2、勾选完成后重启Android Studio。 3、重启完成后&#xff0c;选中要打包的module 4、打包完成 使用 1.在项目中新建libs,放入aar文件。 2.修改配置 添加如下代码 flatDir {dirs("libs")}3.修改app…...

TDengine 快速体验(Docker 镜像方式)

简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能&#xff0c;本节首先介绍如何通过 Docker 快速体验 TDengine&#xff0c;然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker&#xff0c;请使用 安装包的方式快…...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

蓝桥杯 2024 15届国赛 A组 儿童节快乐

P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡&#xff0c;轻快的音乐在耳边持续回荡&#xff0c;小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下&#xff0c;六一来了。 今天是六一儿童节&#xff0c;小蓝老师为了让大家在节…...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

OPENCV形态学基础之二腐蚀

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

安卓基础(aar)

重新设置java21的环境&#xff0c;临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的&#xff1a; MyApp/ ├── app/ …...

CSS设置元素的宽度根据其内容自动调整

width: fit-content 是 CSS 中的一个属性值&#xff0c;用于设置元素的宽度根据其内容自动调整&#xff0c;确保宽度刚好容纳内容而不会超出。 效果对比 默认情况&#xff08;width: auto&#xff09;&#xff1a; 块级元素&#xff08;如 <div>&#xff09;会占满父容器…...