赞
踩
目录
前言:
写在前面,还是一样,最后会给出主要页面代码,本文章记录了写代码中遇到的问题,以及解决过程和解决方法,相信小伙伴们看后能收获颇多~
下面添加的代码分析:
在script块中定义默认用户信息的变量user,这个变量有两个属性,一个为username和pwd,再定义接受用户的信息的变量loginform,注意这次两个属性初始值为空字符串。同时在上方template块中的<el-input>
组件的标签中,添加v-model="loginform.username"
,以实现与 Vue 实例中loginform
对象中username
属性的双向数据绑定。并在登录button中添加点击事件,实现点击按钮时触发 Vue 实例中名为commit
的表达式
(1)导入element样式”消息提示ELMessage“,并定义一个函数表达式,它将一个匿名函数赋值给变量 commit,在该函数中判断,如果账号密码相同,则弹出登录成功!否则,则弹出失败,代码如下:
补充知识1:
我们都知道,在 JavaScript 中,函数可以通过两种主要方式定义:函数表达式和函数声明。
function conmmit(){ } //这个是函数声明
var commit=function(){ } //这个是函数表达式
上面两行代码中都定义了一个名为commit的函数,他们有什么区别呢?如下:
①函数声明:用这种方式定义的函数,我们既可以在 声明前调用函数,也可以在 声明后调用该函数。是由于在代码执行之前,解释器会先读取函数的声明,所以声明前调用函数并不会产生语法错误,这个特征叫做函数声明提升。
下面举一个在函数声明前调用该函数的例子
// 调用函数声明前调用函数 console.log(add(2, 3)); // 输出: 5 // 函数声明 function add(a, b) { return a + b; } // 在函数声明后调用函数 console.log(add(5, 7)); // 输出: 12②函数表达式:是指将一个匿名函数赋值给一个变量。这种方式不会被提升,因此必须在定义之后调用,即在使用匿名函数之前,必须先进行赋值操作,否则将会引起错误。
// 尝试在定义前调用函数表达式 console.log(subtract(2, 3)); // TypeError: subtract is not a function // 函数表达式 var subtract = function(a, b) { return a - b; }; // 在函数表达式定义后调用函数 console.log(subtract(5, 7)); // 输出: -2为什么会引起错误?当你尝试在赋值之前调用一个函数表达式时,JavaScript 会认为你在调用一个未定义的函数。这是因为变量声明被提升,但初始化仍然在原来的位置。因此,在函数表达式赋值之前,变量
subtract
的值是undedefined
作为fined
,调用un
函数会导致错误。
(2)发现输入不了字,用户输入不了数据,因为输入那一直默认是空字符串,我们引入ref来定义响应式变量,实现数据的修改与访问。引入 ref,为变量都用上ref,使其变成响应式数据,下面函数访问也对应的添加上.value来访问该属性的值
发现能输入数据了,但是是明文,所以修改一下密码那的type为password
知识点补充2:
Vue3中Ref与Reactive详解
①ref
是Vue3提供的一个基础响应式API,用于创建一个包装过的响应式对象。通过ref
,我们可以轻松地将一个普通值变成一个可响应的对象。②
reactive
是Vue3提供的另一个响应式API,与ref
相比,reactive
更适用于包裹复杂的对象,使得对象内部的各个属性都变成响应式的。③创建 Ref。在 Vue 3 中,可以使用
ref
函数来创建一个Ref
,如下所示:
import { ref } from 'vue'; const count = ref(0); // 创建一个 Ref,初始值为 0④访问 Ref。通过
value
属性来访问和修改Ref
的值:
console.log(count.value); // 访问 Ref 的值 count.value++; // 修改 Ref 的值⑤在模板中使用
Ref
。直接访问Ref
对象即可,Vue 会自动处理value
属性:
<template> <p>{{ count }}</p> <button @click="count++">Increment</button> </template> <script> import { ref } from 'vue'; export default { setup() { const count = ref(0); return { count }; } }; </script>⑤Ref 的特性
Ref
对象本质上是一个包装器,通过.value
访问和修改内部值。- 自动追踪其引用的变化,并在视图中进行响应更新。
⑥创建 Reactive 对象。在 Vue 3 中,可以使用
reactive
函数来创建一个响应式代理对象:
import { reactive } from 'vue'; const state = reactive({ count: 0, message: 'Hello Vue' });⑦访问 Reactive 对象。直接访问和修改
Reactive
对象的属性即可,无需额外的.value
属性:
console.log(state.count); // 访问 Reactive 对象的属性 state.count++; // 修改 Reactive 对象的属性⑧在模板中使用
Reactive
对象,直接访问对象的属性即可:
<template> <p>{{ state.count }}</p> <button @click="state.count++">Increment</button> </template> <script> import { reactive } from 'vue'; export default { setup() { const state = reactive({ count: 0 }); return { state }; } }; </script>⑨Reactive 的特性
Reactive
可以包含任意深度的嵌套对象,所有嵌套属性都将具有响应性。- Vue 3 使用 Proxy 实现响应式,可以捕获对象的读取、写入和删除等操作。
⑩区别和适用场景
- Ref 适合管理单个基本类型值,如数字、布尔值等,通过
.value
属性访问和修改。- Reactive 适合管理复杂的对象和数组结构,使整个对象及其属性具有响应性。
(1)新建文件,index.vue,这个就是首页的文件名,并为其添加三大块结构
(2)修改路由。在index.js文件做如下修改,使得访问该网页先访问首页
知识点补充3:
在 Vue.js 和 Vue Router 中,路由定义可以采用多种方式来引入组件,这里说一下我常用的两个
①静态引入组件:在应用启动时就会引入所有路由定义的组件。即使用户没有访问某个路由对应的页面,该页面的组件也会被提前加载。
import HomeView from '../views/HomeView.vue'; import AboutView from '../views/AboutView.vue'; const routes = [ { path: '/', component: HomeView }, { path: '/about', component: AboutView } ];②按需引入组件(懒加载):使用动态
import
语法,当用户访问特定路由时,才会加载相应的组件。这种方式通常称为懒加载
const routes = [ { path: '/', component: () => import('../views/HomeView.vue') }, { path: '/about', component: () => import('../views/AboutView.vue') } ];③使用场景
- 静态引入:适用于核心页面或非常小的应用,组件数量不多且需要快速加载。
- 按需引入:适用于大型应用或有大量路由的应用,通过懒加载可以显著优化性能和用户体验。
我们整体是上下结构,上面是顶部导航栏,下面左侧是菜单,右侧是展示的数据
查看其对应源码,仿写,element-plus中如下图:
代码编写如下:效果在第二张图,我们先编写的导航栏,发现导航栏左右两侧的白色背景并没有填充到头,怎么解决呢
我们去查看element源码,发现没啥问题,又去写好的网页上右键-->检查-->选择元素工具(一个箭头),发现header的class样式中的el-header-padding属性导致两边有间隔,这个时element的全局样式,我们访问不了,所以我们在自己的代码中直接为header添加局部样式,强制修改这个属性为0,发现就没有空白了,解决!发现错误的方式在第一张图,修改的代码在第二张图,效果在第三张图
知识点补充:
padding
和margin
区别
①共同点:是 CSS 中用于设置元素间隔的两种不同属性②区别(定义):
padding
用于设置元素内容与元素边框之间的内边距。它增加了元素的可点击区域,但不会影响元素的外部间距。
margin
用于设置元素边框外部与其他元素或容器边界之间的外边距。它用于元素之间的间距,不会影响元素的内部内容。
通过编写逻辑,实现访问首页的时候检查登陆状态,未登录则跳转登录
代码解析:在script块中写逻辑,在下面的代码中分为四部分:
序号①是引入所需的ref,onMounted函数,引入路由,并将获得路由实例赋值给router。
序号②部分先是打印了传过来的JSON对象,然后打印了传过来的JSON对象转换成JS对象,将他们都输出在console控制台上。
序号③部分是写了检查是否登录的函数,第一行用三目运算符来做了一个判断,如果从本地存储中得到键名为loginInfo(可以理解为关键字)的本地存储项,则为真,则把这个本地存储项从JSON对象转换为JS对象并赋值给loginUser,如果没有获取到,则返回null,赋值给loginUser,第三行做了一个判断,如果loginUser的为空,为真,再取反,则为假,则跳转到登陆页,否则则不跳转,实际实现了发现本地存储中没有登录的信息,则跳转去登陆,若有,则不跳转
注意在序号③中loginUser值的取反内部过程:
if (!loginUser) 中的 !loginUser 表达式会首先将 loginUser 的值转换为布尔类型。根据i的语句做判断时隐式转换规则得(紧后面补充知识点中有):
如果 loginUser 的值是 null 或者 undefined,它会被转换为 true,因为 null 和 undefined 是假值。
如果 loginUser 的值是一个对象或者其他非假值,它会被转换为 false,因为非假值被视为真值。
序号④这部分是通过onMounted
钩子确保在组件渲染完成后立即执行 checkLogin()
函数
在login.vue中的script块中编写如下代码
在template块中写下面的布局
在script块中编写这个函数,就是把存储的用户信息删除,调用checkLogin函数,再次检测是否登录,则实现了退出
下面这三块的写法好处:
有个问题:大家可以看一下,我明明传过来的是username,但是显示的时候却是得调用userName,在首页部分打印了一下传过来的值
console.log(localStorage.getItem("loginInfo"));
console.log(JSON.parse(localStorage.getItem('loginInfo')))
发现传过来是大写的userName
查了好多原因,原来传过来的时候是userName(就是我原来传过一次,后来为了格式相同,就改了),改了之后,但是浏览器的本地存储是存着原来的名(userName),所以名字并没有修改成功,只要清理一下本地内存即可,清理的方法如下:
接着修改下面代码即可
效果如下:
效果如下:
定义了一个响应式的数组来存储用户登录信息对象,暂且定义了三个。,如下:
修改登陆按钮的点击事件函数
最后效果如下:
发现有多个用户后,显示登录成功和登陆失败,都显示,而且当前用户的username也不显示,检查了一下,发现当我输入username,pwd,会遍历所有的登录信息,来匹配,匹配不上就会显示登陆失败,所以会显示多个登陆成功,登陆失败
解决方法!:写一个存在测试,查看是否存在一个登录信息与匹配,不是要获得这个值,如果有的话才获得这个值,(这个值就是登陆信息),修改代码如下:
发现解决了,右边登录账号名称也显示了
来解释一下这两段代码的逻辑区别:
修改前的代码:在每次循环中如果当前用户不匹配就显示错误信息,这意味着如果正确用户在列表的最后一个位置,前面的每一次循环都会错误地显示错误信息。
修改后的代码︰只在所有用户检查完毕且未找到匹配用户时才显示错误信息。
补充知识5:
①LocalStorage(本地存储)常用函数
本地存储(Local Storage) 是一种更现代的客户端存储方式,提供了更大的存储空间,不会自动发送到服务器。
// 设置一个本地存储项 localStorage.setItem('username', 'John Doe'); // 读取一个键名为username的本地存储项 console.log(localStorage.getItem('username')); // 删除一个本地存储项 localStorage.removeItem('username'); // 清除所有本地存储项 localStorage.clear();②本地存储和cookie的区别:
③在 JavaScript 中, 条件语句(如 if 语句)在判断表达式时会进行隐式类型转换,将表达式的值转换为布尔类型。这种类型转换遵循以下规则:
特性 Cookie 本地存储(Local Storage) 存储大小 约 4KB 约 5MB 生命周期 可设置过期时间 永久存储,除非手动删除 作用域 特定域名和路径 相同域名 数据传输 每次请求时自动发送给服务器 仅存储在客户端,不自动发送 使用场景 会话管理、用户偏好、跟踪和分析 持久化数据、大量数据、本地配置
隐式类型转换:表达式在条件语句中使用时,会自动转换为布尔类型。具体规则如下:④ JSON对象和JS对象互相转换方法:
- 假值:当表达式的值为假值时,条件为假(即 false)。JavaScript 中的假值包括 false、null、undefined、空字符串 ''、数字 0、NaN。
- 真值:除了假值之外的所有值都被视为真值(即 true)。
JavaScript 对象可以通过 JSON.stringify() 方法转换为 JSON 字符串,而 JSON 字符串可以通过 JSON.parse() 方法转换为 JavaScript 对象。
⑤JSON对象和JS对象实例
JS:JSON:
const person = { name: 'John', age: 30, hobbies: ['reading', 'swimming'], address: { city: 'New York', zip: 10001 }, greet: function() { return `Hello, my name is ${this.name}.`; } };
{ "name": "John", "age": 30, "hobbies": ["reading", "swimming"], "address": { "city": "New York", "zip": 10001 } }
给顶部导航栏添加一个时间,使它显示当前时间,新建文件夹common,在里面新建文件util.js,获取当前时间,并定义显示的格式,并导出,在index.vue中调用这个函数(先引入这个文件)
在script块中编写如下:
在template块中添加这个表达式
效果如下:
发现时间月份应该+1,因为现在是6月,其他时间应该显示两位数 ,年月日的日没有显示出来,再次修改:
①在util.js文件里添加判断,当少于两位数时,就补0,如下:
②在index.vue中的script块中做如下修改:就是把那个定时函数写道init()函数里,由init函数加载到onMounted函数里面。
效果实现后,就是,每秒都变数字,自动变,不用刷新页面。
补充知识6:
①解释util.js导出函数:
SimpleDateFormat: SimpleDateFormat 的具体含义:
在 export default { SimpleDateFormat: SimpleDateFormat } 中:
属性名: SimpleDateFormat 是对象的属性名。
属性值: SimpleDateFormat 是前面定义的函数。
在这种情况下,SimpleDateFormat 是一个函数,作为对象的属性值被导出。这样就可以,当你在其他文件中导入这个模块时,可以通过对象的属性名来访问和调用SimpleDateFormat 函数。②
setInterval
函数解释:
这个函数是一个JavaScript 内置的函数,用于设置一个周期性调用函数的定时器。它会在指定的时间间隔(以毫秒为单位)重复执行一个函数。③@在路径中的使用
在 Vue 项目中,@
通常是一个路径别名,指代项目的根目录(src
目录)。这种路径别名可以使导入模块的路径更加简洁和易读,而不必使用相对路径(如../../
)。
- <template>
- <div class="login-container dis-h">
- <div class="login-form dis-h">
- <div class="dis-v left">
- <span> 欢迎~ </span>
- <span> 智慧农业物联网 </span>
- </div>
- <div class="dis-v right">
- <div class="username dis-h">
- <el-input placeholder="请输入用户名" prefix-icon="User" v-model="loginform.username" />
- </div>
- <div class="pwd dis-h">
- <el-input type="password" placeholder="请输入密码" prefix-icon="Lock" v-model="loginform.pwd" />
- </div>
- <div class="btn dis-h">
- <el-button size="large" style= "width:220px; background-color:#626aef; color:#fff; font-weight:bold;" @click="commit" >
- 登录
- </el-button>
- </div>
- </div>
- </div>
- </div>
- </template>
- <script setup>
- import { User,Lock } from '@element-plus/icons-vue'
- import { ElMessage } from 'element-plus'
- import {useRouter} from 'vue-router'
- import { ref } from 'vue'
-
- var router=useRouter();
- // 定义默认的用户数据
- var userList =ref([
- {
- username:"111",
- pwd:"111"
- },
- {
- username:"222",
- pwd:"222"
- },
- {
- username:"333",
- pwd:"333"
- }
- ]
-
- )
- // 接收用户输入的数据
- var loginform=ref({
- username:"",
- pwd:"",
- })
-
- // 验证用户输入的用户名和密码是否和内部存储的数据一样
- var commit=function(){
- // 循环遍历数组的每一个元素,并将每个元素依次赋值给 item。在循环体内,
- for(var item of userList.value ){
- if(item.username==loginform.value.username&&item.pwd==loginform.value.pwd){
- var has_user=true;
- break;
- }
- }
- if(has_user){
- localStorage.setItem("loginInfo",JSON.stringify({username:loginform.value.username}));
- ElMessage.success("登陆成功!");
- router.replace({
- path:"/"
- })
- }else{
- ElMessage.error("登陆失败!");
- }
- }
-
-
- </script>
- <style >
- .login-container{
- width: 100vw;
- height: 100vh;
- background-image: url('../assets/bg.png');
- background-size: 100%;
- align-items: center;
- justify-content: center;
- }
- .login-form{
- width: 600px;
- height: 300px;
- /* background-color: red; */
-
- }
- .login-form .left{
- width: 50%;
- height: 100%;
- align-items: left;
- justify-content: center;
- font-size: 1.6rem;
- font-weight: bold;
- background:linear-gradient(to right bottom,rgba(136,209,234,0.80) 5%,rgba(215,193,187,0.80) 100% );
- color: #fff;
- text-indent:1rem;
- }
- .login-form .right{
- width: 50%;
- height: 100%;
- background-color: rgba(255, 255, 255, 0.90);
- align-items: center;
- justify-content: center;
- }
- .login-form .username,.pwd,.btn{
- padding: 0.5rem 0;
-
- }
- </style>

- <template>
- <div class="dis-h">
- <el-container class="index-container" >
- <el-header class="index-header" >
- <div class="dis-h" style="width:100%; height:100%;">
- <div class="dis-h" style="width:200px;height:100%; align-items:center;justify-content: center;background-color:#fff;margin-right:5px;border-radius:3px">
- 智慧农业物联网
- </div>
- <div class="dis-h" style="background-color:#fff;height:100%;width:100%;border-radius:3px;align-items:center; justify-content: right;font-size: 0.65rem;">
- <div class="dis-h " style="padding-right:15px; " >
- <span style="color:#000000; ">{{ dateTime }}</span>
- </div>
- <div class="dis-h " style="padding-right:15px; " >
- <span style="color:#000000; ">{{ userInfo.username }}</span>
- </div>
- <div class="dis-h " style="padding-right:45px; " >
- <span style="color:#ff6666;" @click="lagout" >退出</span>
- </div>
- </div>
- </div>
- </el-header>
- <el-container>
- <el-aside >
- Aside
- </el-aside>
- <el-main>
- Main
- </el-main>
- </el-container>
- </el-container>
- </div>
- </template>
- <script setup>
- import{ref,onMounted} from 'vue'
- import {useRouter} from 'vue-router'
- import util from '@/common/util'
- var router =useRouter();
-
- var userInfo =ref({})
- //定义时间变量,并用定时器定时执行获取时间函数
- var dateTime = ref(util.SimpleDateFormat())
-
-
-
- // console.log(localStorage.getItem("loginInfo"));
- // console.log(JSON.parse(localStorage.getItem('loginInfo')))
- var checkLogin =function(){
- let loginUser = localStorage.getItem("loginInfo")?JSON.parse(localStorage.getItem('loginInfo')):null;
- if(!loginUser){
- router.replace({
- path:'/login'
- })
- }else{
- userInfo.value = loginUser;
- }
- }
-
- var lagout=function(){
- localStorage.clear();
- checkLogin();
- }
-
- var init=function(){
- checkLogin();
- setInterval(function(){
- dateTime.value= util.SimpleDateFormat()
- },1000)
- }
-
- onMounted(function(){
- init();
-
- })
- </script>
- <style >
- .index-container{
- width:100vw;
- height: 100vh;
- background-color: #d8d8d8;
- }
- .index-header{
- --el-header-padding: 5px 5px !important;
- /* 上右下左 */
- --el-header-height: 50px !important;
-
- }
-
-
- </style>

-
- function SimpleDateFormat(){
- var now =new Date();
- return now.getFullYear()+"-"+fill(now.getMonth()+1)+"-"+fill(now.getDate())+
- "-"+fill(now.getHours())+"-"+fill(now.getMinutes())+"-"+fill(now.getSeconds());
- }
-
- function fill(str){
- if(str.toString().length<2){
- return "0"+str;
- }else{
- return str;
- }
- }
- export default{
- SimpleDateFormat:SimpleDateFormat
- }

这篇文章就到这里啦~ 下篇文章再见~
结束~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。