React-Native 创建密码管理器
本文将演示如何使用React-Native创建一个密码管理应用程序。为了帮助用户安全存储和管理密码,我们将使用React Native开发一个密码管理移动应用。该应用将提供添加、查看、复制和删除存储密码等功能。
让我们来看看我们完成的项目的外观:
前提条件
- React Native简介
- React Native组件
- React Hooks
- Node.js和Npm
创建React Native应用的步骤
步骤1: 创建一个React Native应用
为JokesGeneratorApp创建一个新的React Native项目。
npx create-expo-app PasswordManagerApp
步骤2:将目录更改为项目文件夹:
cd PasswordManagerApp
项目结构
Package.json
{
"dependencies": {
"react-native-paper": "4.9.2",
"@expo/vector-icons": "^13.0.0",
"react-native-vector-icons/FontAwesome": "*",
"react-native-vector-icons": "10.0.0"
}
}
方法
这个React Native应用程序作为一个密码管理器。它允许用户添加、编辑、复制和删除各种网站的密码。该应用程序维护一个密码列表,每个密码包含网站详细信息、用户名和掩码密码。用户可以将网站名称、用户名和掩码密码复制到剪贴板以便快速访问。该应用程序提供一个编辑功能,通过点击“编辑”按钮来启动,使用户可以修改现有密码。
示例: 这个示例演示了一个基本的密码管理器,其中
- 函数“maskPassword”接收一个密码字符串作为输入,并返回用星号屏蔽的相同密码。
- 这个 copyText 函数使用户可以轻松地复制文本,例如网站URL、用户名和密码,到剪贴板中。此外,它还设置了一个临时弹出消息,名为“alertVisible”,通知用户文本已成功复制。
- deletePassword 函数允许用户删除一个密码条目。它过滤密码数组,消除指定的密码,并提供一个成功的消息。
- editPassword 函数在用户打算修改现有密码条目时调用。它激活编辑标志,从而改变“保存密码”按钮的行为。
- renderPasswordList 函数基于密码数组中的数据生成密码条目列表。然后将每个密码条目映射到一个包含详细信息的视图,例如网站、用户名和复制按钮。
import React, { useState, useEffect } from "react";
import {
View,
Text,
TextInput,
TouchableOpacity,
ScrollView,
StyleSheet,
Clipboard,
} from "react-native";
import Icon from "react-native-vector-icons/FontAwesome";
import { styles } from "./styles";
const App = () => {
const [website, setWebsite] = useState("");
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [passwords, setPasswords] = useState([]);
const [alertVisible, setAlertVisible] = useState(false);
const [editing, setEditing] = useState(false);
const [editIndex, setEditIndex] = useState(null);
useEffect(() => {
showPasswords();
}, []);
const maskPassword = (pass) => {
let str = "";
for (let index = 0; index < pass.length; index++) {
str += "*";
}
return str;
};
const copyText = async (txt) => {
try {
await Clipboard.setString(txt);
setAlertVisible(true);
setTimeout(() => {
setAlertVisible(false);
}, 2000);
} catch (error) {
console.error("Error copying text:", error);
}
};
const deletePassword = (website) => {
const updatedPasswords = passwords.filter(
(e) => e.website !== website
);
setPasswords(updatedPasswords);
alert(`Successfully deleted ${website}'s password`);
};
const showPasswords = () => {
setPasswords([]);
setWebsite("");
setUsername("");
setPassword("");
setEditing(false);
setEditIndex(null);
};
const savePassword = () => {
// Check if any of the input fields is empty
if (!website || !username || !password) {
alert("Please fill in all fields.");
return;
}
if (editing && editIndex !== null) {
const updatedPasswords = [...passwords];
updatedPasswords[editIndex] = {
website,
username,
password,
};
setPasswords(updatedPasswords);
setEditing(false);
setEditIndex(null);
} else {
const newPassword = {
website,
username,
password,
};
setPasswords([...passwords, newPassword]);
}
setWebsite("");
setUsername("");
setPassword("");
};
const editPassword = (index) => {
setEditing(true);
setEditIndex(index);
setWebsite(passwords[index].website);
setUsername(passwords[index].username);
setPassword(passwords[index].password);
};
const renderPasswordList = () => {
return passwords.map((item, index) => (
<View style={styles.passwordItem} key={index}>
<View style={styles.listItem}>
<Text style={styles.listLabel}>
Website:
</Text>
<Text style={styles.listValue}>
{item.website}
</Text>
<TouchableOpacity
style={styles.copyIcon}
onPress={() =>
copyText(item.website)
}>
<Icon
name="copy"
size={20}
color="#555"/>
</TouchableOpacity>
</View>
<View style={styles.listItem}>
<Text style={styles.listLabel}>
Username:
</Text>
<Text style={styles.listValue}>
{item.username}
</Text>
<TouchableOpacity
style={styles.copyIcon}
onPress={() =>
copyText(item.username)
}>
<Icon
name="copy"
size={20}
color="#555"/>
</TouchableOpacity>
</View>
<View style={styles.listItem}>
<Text style={styles.listLabel}>
Password:
</Text>
<Text style={styles.listValue}>
{maskPassword(item.password)}
</Text>
<TouchableOpacity
style={styles.copyIcon}
onPress={() =>
copyText(item.password)
}>
<Icon
name="copy"
size={20}
color="#555"/>
</TouchableOpacity>
</View>
<View style={styles.buttonsContainer}>
<TouchableOpacity
style={styles.editButton}
onPress={() => editPassword(index)}>
<Icon
name="edit"
size={20}
color="#fff"/>
</TouchableOpacity>
<TouchableOpacity
style={styles.deleteButton}
onPress={() =>
deletePassword(item.website)}>
<Icon
name="trash"
size={20}
color="white"/>
</TouchableOpacity>
</View>
</View>
));
};
return (
<ScrollView style={styles.container}>
<View style={styles.content}>
<Text style={styles.heading}>
Password Manager
</Text>
<Text style={styles.subHeading}>
Your Passwords
{alertVisible && (
<Text id="alert"> (Copied!)</Text>
)}
</Text>
{passwords.length === 0 ? (
<Text style={styles.noData}>
No Data To Show
</Text>
) : (
<ScrollView horizontal>
<View style={styles.table}>
{renderPasswordList()}
</View>
</ScrollView>
)}
<Text style={styles.subHeading}>
{editing
? "Edit Password"
: "Add a Password"}
</Text>
<TextInput
style={styles.input}
placeholder="Website"
value={website}
onChangeText={(text) =>
setWebsite(text)
}/>
<TextInput
style={styles.input}
placeholder="Username"
value={username}
onChangeText={(text) =>
setUsername(text)}/>
<TextInput
style={styles.input}
placeholder="Password"
secureTextEntry={true}
value={password}
onChangeText={(text) =>
setPassword(text)
}/>
<TouchableOpacity
style={styles.submitButton}
onPress={savePassword}>
<Text style={styles.submitButtonText}>
{editing
? "Update Password"
: "Add Password"}
</Text>
</TouchableOpacity>
</View>
</ScrollView>
);
};
export default App;
// styles.js
import { StyleSheet } from "react-native";
const styles = StyleSheet.create({
container: {
flex: 1,
margin: 20,
},
content: {
margin: 15,
},
heading: {
fontSize: 30,
fontWeight: "bold",
marginBottom: 15,
textAlign: "center",
color: "#333",
},
subHeading: {
fontSize: 23,
fontWeight: "bold",
marginBottom: 10,
color: "#333",
},
noData: {
fontSize: 17,
fontStyle: "italic",
marginBottom: 20,
color: "#666",
},
table: {
flexDirection: "row",
backgroundColor: "white",
borderRadius: 15,
elevation: 4,
marginBottom: 20,
shadowColor: "grey",
shadowOffset: { width: 0, height: 0 },
shadowRadius: 5,
shadowOpacity: 1,
},
passwordItem: {
flexDirection: "column",
alignItems: "center",
borderBottomWidth: 1,
borderBottomColor: "#ddd",
padding: 15,
},
listItem: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
marginRight: 10,
marginBottom: 10,
},
listLabel: {
fontWeight: "bold",
marginBottom: 5,
color: "#333",
fontSize: 19,
},
listValue: {
flex: 1,
fontSize: 18,
color: "#444",
paddingLeft: 10,
},
copyIcon: {
marginRight: 10,
paddingLeft: 10,
},
deleteButton: {
backgroundColor: "red",
borderRadius: 4,
padding: 5,
marginLeft: 10,
},
editButton: {
backgroundColor: "blue",
borderRadius: 4,
padding: 5,
marginRight: 10,
},
buttonsContainer: {
flexDirection: "row",
},
input: {
borderWidth: 2,
borderColor: "#eee",
paddingVertical: 10,
paddingHorizontal: 15,
marginBottom: 20,
fontSize: 16,
borderRadius: 10,
backgroundColor: "white",
shadowColor: "grey",
shadowOffset: { width: 0, height: 0 },
shadowRadius: 10,
shadowOpacity: 1,
elevation: 4,
},
submitButton: {
backgroundColor: "green",
color: "white",
fontWeight: "bold",
borderRadius: 10,
paddingVertical: 15,
paddingHorizontal: 30,
shadowColor: "black",
shadowOffset: { width: 2, height: 2 },
shadowRadius: 15,
shadowOpacity: 1,
elevation: 4,
},
submitButtonText: {
color: "white",
textAlign: "center",
fontSize: 18,
},
});
export { styles };
运行步骤
要运行React Native应用程序,请使用以下命令:
npx expo start
- 在Android上运行:
npx react-native run-android
- 在iOS上运行:
npx react-native run-ios
输出 :