需求:
实现login登录页输入用户名和密码, 匹配失败显示提示信息, 成功则跳转到index主页
index页面中各组件通过嵌套路由实现,点击一级菜单可以动态显示二级菜单
1.使用vite搭建项目
安装初始化npm init vue@latest
选择配置
进入项目目录,安装模块npm i, 启动项目npm run dev
2.项目目录
删除项目中不需要的组件, 清空不需要的css 文件(将src/assets/main.css中的样式删除)
3. 实现登录页跳转
(1)创建登录页组件src / components / Login.vue ,创建Index.vue
<template>书写登录页html
<style>书写样式, 使用display: flex; 盒子自动变为行内块元素
<script>中data(){ return{ 保存数据 } }, methods:{ 内部书写各种函数}
输入用户名和密码时, input表单元素, 需要通过v-model 进行双向数据绑定, 可通过修饰符 .trim 去除前后空格
响应式数据, 保存在data函数中并通过return返回对象
登录按钮绑定点击事件, 并触发login登录函数
login登录函数的实现:
获取输入框内容, 判断是否为空
为空: 显示提示信息
不为空: 判断用户名和密码是否正确
正确: 实现页面跳转, 使用this.$router.push()/replace()
不正确: 显示提示信息
<template><div class="login"><div class="box"><h1>Login</h1><ul><li><label><span>用户名</span>:<!-- 1. 动态绑定 .trim去空 --><input type="text" v-model.trim="uname" placeholder="请输入用户名"></label></li><li><label><span>密码</span>:<input type="password" v-model.trim="password" placeholder="请输入密码"></label></li><li class="tips" v-show="isShow">{{ tips }}</li><li><button @click="login">登 录</button></li></ul></div></div>
</template>
<script>export default {data() {return {uname: '',password: '',tips: '',isShow: false, //控制tips是否显示, false默认不显示}},methods: {// 登录login() {// 2 .获取用户名和密码的值, 判断是否存在if (this.uname === '' || this.password === '') {// 3. 用户名或密码为空this.isShow = true //显示tipsthis.tips = '用户名或密码不能为空 ! ! !'} else {this.isShow = false// 4. 用户名或密码不为空 , 判断用户名和密码是否正确if (this.uname === 'mm' && this.password === '1111') {// 5. 用户名和密码正确, 跳转页面this.$router.push({path: '/index'})} else {// 6. 用户名或密码不正确this.isShow = true //显示tipsthis.tips = '用户名或密码错误 ! ! !'}}}}}
</script>
<style scoped>div.login {display: flex;height: 100%;justify-content: center;align-items: center;}div.login div.box {width: 30%;height: 40%;background-color: #ffede7;}div.login div.box h1 {margin-top: 30px;text-align: center;}div.login div.box ul {position: relative;text-align: center;font-size: 20px;}div.login div.box ul li {margin: 30px auto;width: 80%;}div.login div.box ul li label {width: 100%;}div.login div.box ul li label span {display: inline-block;margin-right: 5px;width: 80px;text-align: justify;text-align-last: justify;text-justify: distribute-all-lines;}div.login div.box ul li label input {width: 65%;height: 40px;font-size: 18px;outline: 0;text-indent: 5px; /* 默认文本值距离左边的距离*/}div.login div.box ul li button {margin-top: 15px;padding: 0 35%;width: 90%;height: 40px;text-align: justify;text-align-last: justify;font-size: 20px;border: 0;cursor: pointer;background-color: #ffe3d5;}div.login div.box ul li.tips {color: deeppink;font-size: 16px;position: absolute;bottom: 20px;left: 35px;}
</style>
页面效果:
(2)启动项目,直接进入Login页面
启动项目打开页面时, 直接进入Login页面, 尝试了一下两种方式
方式1: 将Login组件作为App.vue的子组件 (有问题)
在App.vue中引入组件
通过components:{}注册组件, 使用大驼峰命名规则
将组件作为标签来使用, 与注册组件名保持一致 <Login></Login>
问题:
(1) 在地址栏中输入任何内容, 都会跳转至登录页面
(2) 在页面进行跳转时, 地址栏中路径变化,但页面无法显示, 依旧为登录页面
[ 无法获取到路由实例 this.$router, 可能是定义路由中history模式没写() ]
原因:
把Login.vue组件作为App.vue中模板的内容, App.vue是项目根组件,作为页面入口, 任何路径都需要从该入口进入
<script>import Login from './components/Login.vue'export default{components:{ Login }}
</script>
<template><div><Login></Login></div>
</template>
<style scoped></style>
方式2: 通过路由实现(解决方式1带来的问题)
定义路由 router/index.js, 创建路由对象, 编写路径与组件的映射关系
import { createRouter, createWebHistory } from 'vue-router'
import Login from '../components/Login.vue'
import Index from '../components/Index.vue'const router = createRouter({
//history模式中 hash模式在地址栏中前边会有一个/# , 并且未被发送到服务器,不需要在服务器层面上进行任何特殊处理history: createWebHistory(import.meta.env.BASE_URL),routes: [{path: '/login',name: 'Login',component: Login,alias: '/'}, {path: '/index',name: 'Index',component: Index,children: [{path: '/index/grade22',name: 'Grade22',component: Grade22,}, ] //此处省略一些子路由的定义}]
})
export default router
在main.js中使用路由
import router from './router'
app.use(router)
在App.vue中使用路由占位符, 指定显示位置
<template><div> <!-- 路由显示的指定区域, 两种标签均可 --><!-- <RouterView></RouterView> --><router-view></router-view></div>
</template>
当输入无效路径时, 显示404页面 ( 创建404组件, 并定义路由 )
$route.params.paths 可获取动态路由参数
$router 指当前活跃的路由实例对象
{// 404 将所有匹配到的路径存放在 $route.params.paths 下, 将非法路径的所有部分作为参数// /:paths(.*)* 无效路径打印后 [ "index", "grade19", "aaa" ] 最后的 * 是将每一部分都分割了 // /:paths(.*) index/grade19/aaapath: '/:paths(.*)*',component: NotFount
}
4.实现主页
一级标签使用超链接(<a>), 点击a标签会造成整个页面的刷新, 性能较低
使用<router-link to="">导航路由完成, 改变地址栏路径, 页面不会重新渲染,性能较高
<template><div class="box"><div class="index"><ul class="title"><router-link to="/index/grade22"><li>2022级</li></router-link><router-link to="/index/grade21"><li>2021级</li></router-link><router-link to="/index/grade20"><li>2020级</li></router-link><router-link to="/index/grade19"><li>2019级</li></router-link></ul><router-view></router-view></div></div>
</template>
在router/index.js中定义路由
发现Index组件中的子组件模板基本一样, 故只创建一个组件, 通过参数传递的方式实现
使用嵌套路由实现, 将Grade.vue 组件的内容显示在Index.vue中
routes: [{path: '/',name: 'Login',component: Login,alias: '/login'},{path: '/index',name: 'Index',component: Index,// redirect: 'grade/22',children: [{path: '/index/grade/:id',name: 'Grade',component: Grade,children: [{path: 'grade/:id/spe',name: 'Specialty',component: Specialty,}]}, ]},{// 404 将所有匹配到的路径存放在 $route.params.paths 下, 将非法路径的所有部分作为参数// /:paths(.*)* 无效路径打印后 [ "index", "grade19", "aaa" ] 最后的 * 是将每一部分都分割了// /:paths(.*) index/grade19/aaapath: '/:paths(.*)*',component: NotFount}]
Grade.vue组件中使用命名路由
<template><div class="specialty"><ul><router-link to="/index/grade/22/spe"><li>计算机</li></router-link><router-link to="/index/grade/21/spe"><li>信管</li></router-link><router-link to="/index/grade/20/spe"><li>信计</li></router-link><router-link to="/index/grade/19/spe"><li>数学</li></router-link></ul><router-view ></router-view></div>
</template>
5.实现点击一级菜单, 动态渲染二级菜单
将导航数据存储在Data.js中
在组件中获取参数, 可通过$route.pramas获取, 也可通过 props:[ ]接收参数
根据参数不同, 加载不同的菜单
<template><div class="specialty"><ul><router-link v-for="item of list" :to="{ name:'specialty', params:{id} }"><li>{{ item }}</li></router-link></ul><router-view></router-view></div>
</template>
<script>import data from '../Data.js';export default {data() {return {list: []}},props: ['id'],// 钩子函数mounted() {const id = this.$route.params.id;//做初始化this.list = data.filter(item => item.id == id)[0].items;},updated() {const id = this.$route.params.id;//更新时也要更新listthis.list = data.filter(item => item.id == id)[0].items;}}
</script>
<style scoped>div.specialty ul {display: flex;background-color: #fff;}div.specialty ul li {padding: 10px 20px 10px 10px;}
</style>
效果图:
源代码放在这里啦~~~(大家帮忙提提点击量呗^^)
https://download.csdn.net/download/qq_54379580/87473605