快速搭建前端页面
1 Vue
前置:
需要先包含node环境
如果没有,可去node官网下载一个并配置
node官网地址:https://nodejs.org/zh-cn/
# 检测是否安装成功node -v
1.1 vue脚手架
- 检测是否有node环境,如果没有则去node官网下载配置【进入cmd执行以下命令】
node -v
- 安装vue脚手架
npm install -g @vue/cli
# 检测是否安装成功vue --version
- 创建项目
# 全局安装初始化命令npm i -g @vue/cli-init# 创建项目vue init webpack 文件夹名称
如果当前文件夹已经存在会提示Target directory exists. Continue? 是否在当前目录下创建,输入yes表示同意
# 项目名Project name -- testpro# 项目描述Project description -- A Vue.js project# 作者Author -- ziyi# build选项Vue build ("通过上下箭头选择")- Runtime+Compiler 运行加编译【建议】- Runtime-only 仅运行# 是否安装路由【输入y或者n即可】Install vue-router(Y/n) # 是否使用ESLint(代码风格校验工具)Use ESLint to lint your code?(Y/n) # 是否设置单元测试Set up unit tests (Y/n) # 是否设置端到端测试Setup e2e tests with Nightwatch (Y/n) # 使用什么管理包Should we run `npm install` for you after the project has been created?- Yes, use NPM (使用npm包管理)- Yes, use Yarn (使用yarn包管理)- No, I will handle that myself (自己处理)
- 项目初始化并启动
切记一定要进入项目的文件夹,否则会报找不到
package.json
cd work(进入项目所在文件夹)# 启动项目npm run dev
5. 连接链接,访问
项目结构:
1.2 vue+elementUi实现注册登录
首先已经通过1.1的vue脚手架搭建好了vue基本框架,通是编写对应js
# 安装element-uinpm i element-ui -S
vue项目结构介绍:
①新建vue文件
新建两个Vue文件,Login.vue和Register.vue
Login.vue:
<template><div class="loginbody"><div class="logindata"><div class="logintext"><h2>Welcome</h2></div><div class="formdata"><el-form ref="form" :model="form" :rules="rules"><el-form-item prop="username"><el-inputv-model="form.username"clearableplaceholder="请输入账号"></el-input></el-form-item><el-form-item prop="password"><el-inputv-model="form.password"clearableplaceholder="请输入密码"show-password></el-input></el-form-item></el-form></div><div class="tool"><div><el-checkbox v-model="checked" @change="remenber">记住密码</el-checkbox></div><div><span class="shou" @click="forgetpas">忘记密码?</span></div></div><div class="butt"><el-button type="primary" @click.native.prevent="login('form')">登录</el-button><el-button class="shou" @click="register">注册</el-button></div></div></div></template><script>import { login } from "@/api/login";export default {name: "Login",data() {return {form: {password: "",username: "",},checked: false,rules: {username: [{ required: true, message: "请输入用户名", trigger: "blur" },{ max: 10, message: "不能大于10个字符", trigger: "blur" },],password: [{ required: true, message: "请输入密码", trigger: "blur" },{ max: 10, message: "不能大于10个字符", trigger: "blur" },],},};},mounted() {if (localStorage.getItem("news")) {this.form = JSON.parse(localStorage.getItem("news"));this.checked = true;}},methods: {login(form) {this.$refs[form].validate((valid) => {if (valid) {login(this.form).then((res) => {if (res.code === 200) {setToken(res.data.token);localStorage.setItem("USERNAME", res.data.username);this.$message({message: "登录成功啦",type: "success",showClose: true,});this.$router.replace("/");} else {this.$message({message: "账户名或密码错误",type: "error",showClose: true,});}}).catch((err) => {this.$message({message: "账户名或密码错误",type: "error",showClose: true,});});} else {return false;}});},remenber(data) {this.checked = data;if (this.checked) {localStorage.setItem("news", JSON.stringify(this.form));} else {localStorage.removeItem("news");}},forgetpas() {this.$message({type: "info",message: "功能尚未开发额",showClose: true,});},register() {//跳转到注册页面this.$router.push({path:`register`})},},};</script><style scoped>.loginbody {width: 100%;height: 100%;min-width: 1000px;background-image: url("../assets/login.png");background-size: 100% 100%;background-position: center center;overflow: auto;background-repeat: no-repeat;position: fixed;line-height: 100%;padding-top: 150px;}.logintext {margin-bottom: 20px;line-height: 50px;text-align: center;font-size: 30px;font-weight: bolder;color: white;text-shadow: 2px 2px 4px #000000;}.logindata {width: 400px;height: 300px;transform: translate(-50%);margin-left: 50%;}.tool {display: flex;justify-content: space-between;color: #606266;}.butt {margin-top: 10px;text-align: center;}.shou {cursor: pointer;color: #606266;}</style>
Register.vue:
<template><div class="login clearfix"><div class="login-wrap"><el-row type="flex" justify="center"><el-form ref="loginForm" :model="user" status-icon label-width="80px"><h3>注册</h3><hr><el-form-item prop="username" label="用户名"><el-input v-model="user.username" placeholder="请输入用户名"></el-input></el-form-item><el-form-item prop="email" label="邮箱"><el-input v-model="user.email" placeholder="请输入邮箱"></el-input></el-form-item><el-form-item prop="password" label="设置密码"><el-input v-model="user.password" show-password placeholder="请输入密码"></el-input></el-form-item><el-form-item><el-button type="primary" icon @click="doRegister()">注册账号</el-button></el-form-item></el-form></el-row></div></div></template> <script>import axios from "axios";export default {name: "login",data() {return {user: {username: "",email: "",password: ""},};},created() {// console.log($);// console.log("1111");},methods: {doRegister() {if (!this.user.username) {this.$message.error("请输入用户名!");return;} else if (!this.user.email) {this.$message.error("请输入邮箱!");return;} else if (this.user.email != null) {var reg = /^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/;if (!reg.test(this.user.email)) {this.$message.error("请输入有效的邮箱!");} else if (!this.user.password) {this.$message.error("请输入密码!");return;} else {// this.$router.push({ path: "/" }); //无需向后台提交数据,方便前台调试axios.post("/register/", {name: this.user.username,email: this.user.email,password: this.user.password}).then(res => {// console.log("输出response.data", res.data);// console.log("输出response.data.status", res.data.status);if (res.data.status === 200) {this.$router.push({ path: "/" });} else {alert("您输入的用户名已存在!");}});}}}}};</script> <style scoped>.login {width: 100%;height: 740px;background-size: cover;overflow: hidden;}.login-wrap {background-size: cover;width: 400px;height: 300px;margin: 215px auto;overflow: hidden;padding-top: 10px;line-height: 20px;} h3 {color: #0babeab8;font-size: 24px;}hr {background-color: #444;margin: 20px auto;} .el-button {width: 80%;margin-left: -50px;}</style>
②新建js文件
login.js:
登录请求是通过引入外部js实现,注册请求则是通过写入vue页面中的script实现,没有做复用【当然也可以封装到外部,写在login.js或register.js中】
import Axios from "axios";import {get, post} from "./http";// post 请求export const login = (params) => post(`login`, params)
③添加路由配置
添加路由配置
router文件夹下的index.js
一定要加上mode: "history"
,同时要import组件
index.js:
import Vue from 'vue'import Router from 'vue-router'import HelloWorld from '@/components/HelloWorld'import Register from '@/components/Register'import Login from '@/components/Login'Vue.use(Router)export default new Router({routes: [// {// path: '/',// name: 'HelloWorld',// component: HelloWorld// },{path:'/',name: 'Login',component: Login},{path: '/register',name: 'Register',component: Register}],mode: "history"})
path:是指跳转路径,name是名称,component是组件名(对应.vue文件)
例如:/register表示如果路径是localhost:8080/register,就跳转到Register.vue文件夹下
④实例化vue对象,引入axios
实例化vue对象,引入需要使用的工具,如:axios、element-ui等
main.js:
import Vue from 'vue'import App from './App'import router from './router'import axios from 'axios'import ElementUI from 'element-ui';import 'element-ui/lib/theme-chalk/index.css'; Vue.use(ElementUI)//全局配置Vue.prototype.$axios = axiosVue.config.productionTip = false /* eslint-disable no-new */new Vue({el: '#app',router,components: { App },template: ''})
⑤效果
登录页面:
注册页面:
图片自取,页面图片,放在assets下,并命名为login.png
:
拓展:操作js(与后端交互)
①封装http请求
src/api/http.js
http.js:
// 封装通用请求import axios from 'axios'import router from '../router'axios.defaults.timeout = 5000 // 超时时间:5saxios.defaults.withCredentials = true// 允许跨域// Content-Type 响应头axios.defaults.headers.post['Content-Type'] = 'application/x-www.form-urlencoded;charset=UTF-8'// 访问基础urlaxios.defaults.baseURL = 'http://localhost:8090'// 响应拦截器axios.interceptors.response.use(response => {// 如果response里面的status是200,说明访问到接口了,否则失败if (response.status === 200) {// Promise:异步框架return Promise.resolve(response)} else {return Promise.reject(response)}},error => {if (error.response.status) {// 根据访问失败返回的状态码,分别做不同的处理switch (error.response.status) {case 401: // 未登录router.replace({path: '/',query: {redirect: router.currentRoute.fullPath // 存之前访问地址}})breakcase 404: // not foundbreak}return Promise.reject(error.response)}})/** * 封装get请求 */export function get (url, params = {}) {return new Promise((resolve, reject) => {axios.get(url, {params: params}).then(response => {resolve(response.data)}).catch(err => {reject(err)})})}/** * 封装post请求 */export function post (url, data = {}) {return new Promise((resolve, reject) => {axios.post(url, data).then(response => {resolve(response.data)}).catch(err => {reject(err)})})}
②定义请求的js
例如文件为:index.js【文件放在src/api/index.js】
//查询所有歌手【普通的get请求,不带参数】export const getAllSinger = () => get(`singer/selectAll`)//根据歌手性别查询【带参数的get请求】export const getSingerOfSex = (sex) => get(`singer/selectSingerOfSex" />${sex}`)//返回当前的评论列表【根据传参发送不同请求】export const getAllComment = (type, id) => {if(type == 0){ //type: 0 歌曲return get(`comment/commentOfSongId?songId=${id}`);}else{ //歌单return get(`comment/commentOfSongListId?songListId=${id}`);}}//新增收藏【post请求】export const setCollect = (params) => post(`collect/add`, params);//下载音乐【异步请求】export const download = (url) => Axios({method: 'get',url: url,responseType: 'blob'})
③在页面中引入并使用
在xxx.vue的标签中引入对应的js
import {getAllSinger} from '../api/index';
在Singer.vue中的script标签中引入对应的js方法,一般我们都会多封装一层【getAllSinger被封装为getSingerList】
// export const getAllSinger = () => get(`singer/selectAll`)<script>import ContentList from "../components/ContentList";import {getAllSinger} from '../api/index';import {mixin} from "../mixins";import {singerStyle} from '../assets/data/singer';export default {name: 'singer',components:{ContentList},data(){return {albumDatas: [], //歌手数据pageSize: 10, //页面大小currentPage: 1,singerStyle:[], //歌手类型activeName: '全部歌手', //当前风格【类型】}},computed:{//计算当前表格中的数据data(){return this.albumDatas.slice((this.currentPage - 1) * this.pageSize, this.currentPage*this.pageSize)}},mounted() {this.singerStyle = singerStyle;this.getSingerList();},methods:{//获取歌手列表getSingerList() {getAllSinger().then(res => {this.currentPage = 1;this.albumDatas = res;})}}}</script>
2 Element-UI
2.1 提交表单
SongListPage.vue:
//html部分<el-dialog title="添加歌单" :visible.sync="centerDialogVisible" width="400px" center> <el-form :model="registerForm" ref="registerForm" label-width="80px"> <el-form-item prop="title" label="标题" size="mini"> <el-input v-model="registerForm.title" placeholder="标题"></el-input> </el-form-item> <el-form-item label="歌单风格" prop="style"> <el-select v-model="registerForm.style" placeholder="请选择歌曲风格"> <el-option label="流行" :value="'流行'"></el-option> <el-option label="摇滚" :value="'摇滚'"></el-option> <el-option label="古典" :value="'古典'"></el-option> </el-select> </el-form-item> </el-form><span slot="footer"><el-button size="mini" @click="centerDialogVisible = false">取消</el-button><el-button size="mini" @click="addSongList">确定</el-button></span></el-dialog>
其中,el-select的registerForm.style对应的是script中data的registerForm的style,el-form-item对应传给后端的属性名
//js 部分<script>import { getAllSongList, setSongList, updateSongList, delSongList} from '../api/index';import {mixin} from '../mixins/index';export default {mixins:[mixin],data: function(){return{registerForm:{//添加框title:'',introduction:'',style: ''},};},methods:{//添加歌单addSongList(){let params = new URLSearchParams();params.append('title', this.registerForm.title);params.append('pic', '/img/songListPic/songList1.png');params.append('introduction', this.registerForm.introduction);params.append('style', this.registerForm.style);setSongList(params).then(res => {if(res.code == 1){this.getData();this.notify("添加成功", "success");} else {this.notify("添加失败", "error");}}).catch(err => {console.log(err);});//添加成功之后清除添加框this.registerForm = {}},}}</script>