一、搜索框与跳转
- element组件: 1.
Tabs标签页 2.Input输入框- 思路:
- 添加
tab布局- 点击
tab栏切换时currentOption记录当前状态变量,判断currentOption是否等于索引index以决定是否给高亮样式.同时搜索框占位符placeholder为当前状态的数据.- 点击放大镜或回车进行搜索时
url传参跳转页面后再匹配数据.- 如果是机票项直接跳转页面.
pages/index.vue组件
template部分
<!-- 搜索框 -->
<div class="banner-content">
<div class="search-bar">
<!-- tab栏 -->
<el-row type="flex" class="search-tab">
<!-- span:每个分类 -->
<!-- options:循环tab的数组数据 -->
<!-- index:索引 -->
<!-- action:样式,索引是否等于当前点击状态,等于布尔值决定是否赋值样式 -->
<!-- handleOption:当前点击的tab,传入索引 -->
<!-- currentOption:当前激活项 -->
<span
v-for="(item, index) in options"
:key="index"
:class="{ active: index === currentOption }"
@click="handleOption(index)"
>
<i>{{ item.name }}</i>
</span>
</el-row>
<!-- 输入框 -->
<!-- placeholder:当前激活项的输入框占位符 -->
<!-- searchValue:动态绑定输入框的值 -->
<!-- handleSearch:点击放大镜或回车键调用事件 -->
<el-row type="flex" align="middle" class="search-input">
<input
:placeholder="options[currentOption].placeholder"
v-model="searchValue"
@keyup.enter="handleSearch"
/>
<i class="el-icon-search" @click="handleSearch"></i>
</el-row>
</div>
</div>
data部分
// 搜索框数据
options: [
{ name: "攻略", placeholder: "搜索城市攻略", pageUrl: "/post?city=" },
{ name: "酒店", placeholder: "搜索城市酒店", pageUrl: "/hotel?city=" },
{ name: "机票", placeholder: "请输入出发地", pageUrl: "/air" },
],
searchValue: "", //搜索框关键词
currentOption: 0, //当前状态选项
methods部分
methods: {
handleSearch() {
console.log("搜索");
// 点击回车或者放大镜时在url里传参,跳转响应页面,再讲参数进行搜索
// searchValue:当前用户输入数据
this.$router.push(
this.options[this.currentOption].pageUrl + this.searchValue
);
},
// 点击tab切换,index:当前点击的索引currentOption:当前激活项
handleOption(index) {
//飞机票因为业务比较复杂,判断如果是机票索引直接跳转
if (index === 2) {
this.$router.push(this.options[index].pageUrl + this.searchValue);
}
this.currentOption = index;
},
},
效果
二、登录注册页布局
思路:
- 点击时获取当前索引赋值给
currentTab- 切换状态保留当前状态赋值
currentTab.- 当索引
index值等同currentTab时,高亮样式
pages/user/login.vue
<template>
<div class="container">
<!-- 主要内容 -->
<el-row type="flex" justify="center" align="middle" class="main">
<div class="form-wrapper">
<!-- 表单头部tab -->
<el-row type="flex" justify="center" class="tabs">
<!-- currentTab:当前点击状态 -->
<!-- index:索引 -->
<!-- handleChangeTab:点击获取当前索引赋值给currentTab -->
<!-- active:为true时赋值active样式 -->
<span
:class="{ active: currentTab === index }"
v-for="(item, index) in [`登录`, `注册`]"
:key="index"
@click="handleChangeTab(index)"
>
{{ item }}
</span>
</el-row>
<!-- 登录功能组件 -->
<!-- <LoginForm v-if="currentTab == 0"/> -->
<!-- 注册功能组件 -->
<!-- <RegisterForm v-if="currentTab == 1"/> -->
</div>
</el-row>
</div>
</template>
<script>
export default {
data() {
return {
currentTab: 0, //当前状态
};
},
methods: {
handleChangeTab(index) {
// 点击获取当前索引赋值给currentTab
this.currentTab = index;
},
},
};
</script>
<style scoped lang="less">
.container {
background: url(http://157.122.54.189:9095/assets/images/th03.jfif) center 0;
height: 700px;
min-width: 1000px;
.main {
width: 1000px;
height: 100%;
margin: 0 auto;
position: relative;
.form-wrapper {
width: 400px;
margin: 0 auto;
background: #fff;
box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.1);
overflow: hidden;
.tabs {
span {
display: block;
width: 50%;
height: 50px;
box-sizing: border-box;
border-top: 2px #eee solid;
background: #eee;
line-height: 48px;
text-align: center;
cursor: pointer;
color: #666;
&.active {
color: orange;
border-top-color: orange;
background: #fff;
font-weight: bold;
}
}
}
}
}
}
</style>
效果
三、form表单组件发送登录请求
- 思路:
form表单布局- 绑定输入框数据
- 表单验证三步走:绑定整个
from表单数据,定义rules校验规则,表单每一项对应prop并设置在el-form-item上。Element------validate表单验证代码示例与校验规则- 获取光标时清除校验提升客户体验.
- 失去焦点一次校验,点击提交二次校验, 通过验证发送登录请求,并给出提示
components/user/LoginForm.vue
<template>
<!-- :model:收集表单数据 -->
<!-- ref:表单标识 -->
<!-- rules:校验用户输入的数据 -->
<!-- el-form-item:输入框 -->
<!-- v-model:绑定该项输入框的值 -->
<!-- prop:必须绑定在el-form-item,这里的username非form.username -->
<!-- focus:聚焦时触发事件 -->
<el-form :model="form" ref="form" :rules="rules" class="form">
<el-form-item class="form-item" prop="username">
<el-input
placeholder="用户名/手机"
v-model="form.username"
@focus="clearUsername"
>
</el-input>
</el-form-item>
<el-form-item class="form-item" prop="password">
<el-input
placeholder="密码"
type="password"
v-model="form.password"
@focus="clearPassword"
>
</el-input>
</el-form-item>
<p class="form-text">
<nuxt-link to="#">忘记密码</nuxt-link>
</p>
<!-- 点击触发事件提交表单 -->
<el-button class="submit" type="primary" @click="handleLoginSubmit">
登录
</el-button>
</el-form>
</template>
<script>
import { login } from "@/components/user/user";
export default {
data() {
return {
form: {
username: "13800138000", //用户名数据
password: "123456", //密码数据
},
//定义校验规则,这是个数组,可以多组校验
rules: {
username: [
{
required: true, //必须传参
message: "请输入合法的手机号/用户名", //不传参时显示字段
trigger: "blur", //失去焦点触发一次校验
},
],
password: [
{
required: true, //必须传参
message: "请输入密码", //不传参时显示字段
trigger: "blur", //失去焦点触发一次校验
},
{
min: 6, //最小6位
message: "密码不能小于六位", //不传参时显示字段
trigger: "blur", //失去焦点触发一次校验
},
],
},
};
},
methods: {
// 提交表单
async handleLoginSubmit() {
// 点击按钮时触发函数二次校验
console.log(this.form);
const valid = this.$refs.form.validate();
//为true发送接口
if (valid) {
const res = await login(this.form);
console.log(res);
//发送成功返回token提示登录成功
if (res.data.token) {
this.$message({
message: "登录成功",
type: "success",
});
} else {
this.$message.error("登录错误");
}
}
},
// 聚焦时移除用户名校验
clearUsername() {
this.$refs.form.clearValidate("username");
},
// 聚焦时移除密码校验
clearPassword() {
this.$refs.form.clearValidate("password");
},
},
};
</script>
<style scoped lang="less">
.form {
padding: 25px;
}
.form-item {
margin-bottom: 20px;
}
.form-text {
font-size: 12px;
color: #409eff;
text-align: right;
line-height: 1;
}
.submit {
width: 100%;
margin-top: 10px;
}
</style>
表单引入pages/user/login.vue
// 引入登录
import LoginForm from "@/components/user/LoginForm";
注册
components: {
LoginForm, //登录表单
},
打开注释的登录组件代码
<!-- 登录功能组件 -->
<LoginForm v-if="currentTab == 0" />
四、封装axios
utils/http.js封装基路径
//创建一个axios
import axios from 'axios'
axios.defaults.baseURL
const http = axios.create({
baseURL: 'http://157.122.54.189:9095'
})
http.interceptors.response
export default http
user/user.js
// 引入基准路径
import axios from '@/utils/http'
//登陆接口,post请求
export const login = (data) => {
return axios({
url: '/accounts/login',
method: 'post',
data
})
}
五、发送登录请求效果
六、vuex管理用户信息步骤(store)
- 创建
store仓库,为后期储存做准备- 登录时判断成功后储存用户信息
- 头部判断储存仓库中有没有用户信息,有的话隐藏登录/注册按钮,渲染用户信息
创建数据仓库store/user.js
// 用户管理
export const state = () => ({
// 采用接口返回的数据结构
userInfo: {
},
})
//修改state里面的数据,必须使用mutations里面的函数
export const mutations = {
userInfo(state, data) {
//每个mutations可以接收到两个参数
//第一个是state对象本身
//第二个是调用函数是额外添加的数据
state.userInfo = data
//外面调用这个函数,并且传入数据,即可改变userInfo
}
};
渲染头部组件components/PageHeader.vue
- 在原先静态登录/注册信息中更改为如下代码
<!-- 如果用户存在则展示用户信息,用户数据来自store -->
<!-- 判断token数据存不存在,存在则显示 -->
<el-dropdown v-if="userInfo.token">
<el-row type="flex" align="middle" class="el-dropdown-link">
<nuxt-link to="#">
<!-- 判断图片有没有,拼接图片路径 -->
<img
v-if="userInfo.user.defaultAvatar"
:src="$axios.defaults.baseURL + userInfo.user.defaultAvatar"
/>
<!-- 渲染名字 -->
{{ userInfo.user.nickname }}
</nuxt-link>
<i class="el-icon-caret-bottom el-icon--right"></i>
</el-row>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>
<nuxt-link to="#">个人中心</nuxt-link>
</el-dropdown-item>
<el-dropdown-item>
<div @click="handleLogout">退出</div>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
computed: {
userInfo() {
return this.$store.state.user.userInfo;
},
}
user/LoginForm表单组件中判断成功储存数据
this.$store.commit("user/userInfo", res.data);
if (res.data.token) {
this.$message({
message: "登录成功",
type: "success",
});
this.$store.commit("user/userInfo", res.data); //储存用户信息
}