前端开发----vue
首先附上Vue生命周期图
一、项目的搭建
使用 vue-cli 脚手架搭建工程步骤步骤:
默认已经安装好npm,我的版本
- 以管理员身份运行cmd,全局安装vue-cli
npm install -g @vue/cli //安装vue cli
vue --version //查看版本
- 选择一个文件目录,存放项目,进入该目录的cmd命令提示符,输入下列命令,等待配置
vue create 工程名(只能使用英文、数字、短横线,不支持中文,特殊字符)
选择预设配置:1.默认;2.手动;(可以使用键盘的上下选择,回车确定配置)
我选择了手动配置…
-
进入下列选项,选择你需要的配置,键盘上下选择,空格确定,回车进入下一个配置
常用配置:
Babel:配置兼容性,可以让ES6+编译为ES5
Router:配置路由
Vuex:状态管理
我只选择了Babel… -
选择完成后,在选择配置放置位置,选择第二个in package.json
-
是否保留预设配置,否N,回车,等待项目搭建完成。
至此一个vue项目搭建完成,就可以关掉命令窗口了
二、项目工程结构
使用HBuilderX从存放目录导入该项目,(–部分为自己创建的,其他是自动生成。
---node-modules ...外部库依赖
---public
---favicon.ico ...vue的图标
---index.html ...静态页面,首页
---src
---main.js ...入口函数
---App.vue ...根组件
---components ...子组件文件夹
---assets ...静态文件夹,如图片等
(--router ...路由配置文件夹
(--service ...请求服务配置文件夹
(--store ...状态管理配置文件夹
(--views ...视图文件夹
---.gitignore ...代码管理仓库地址
---babel.config.js ...配置兼容性
---package.json ...工程信息,如外部依赖,项目版本等
---package-lock.json ...依赖版本
---README.md ...说明文档
点击HX功能栏(运行–>运行到终端–>1.npm run build–构建打包项目;2.npm run server–构建完成直接运行 )
也可以在该目录的cmd中,输入这些命令,最后获得项目的服务器地址
初始项目效果如图
三、开始编码工作
- 安装可能需要的依赖,进入工程目录的cmd,安装vue-router,vuex,axios
npm i vue-router //路由
npm i vuex //状态管理
npm i axios //http库
- 项目文件内容
- 在src目录下,新建文件夹views–视图层,之下新建Login.vue(登录页面)、Personal.vue(个人中心页面,登录成功后方可进入)、Auth.vue(登录验证页面,受保护的页面如Personal.vue必须进过该页面验证才能进入)、NotFound.vue(404页面)、Example1…2…3.vue(three.js小案例)
- 在src目录下,新建文件夹router–路由配置,之下新建index.js(路由基本配置),新建文件夹store–状态管理,之下新建index.js(状态管理基本配置)、loginUser.vue(登录用户状态管理),新建文件夹service(http请求服务),之下新建userService.js(用户登录请求服务)。
- 在components子组件下,Center.vue实现任意内容居中,FormError.vue实现表单错误提示
- 代码部分
①配置路由
src/router/index.js,路由配置文件
import Vue from "vue"; //引入Vue
import VueRouter from "vue-router"; //引入vue-router
import store from "../store";
//1.安装
Vue.use(VueRouter);
//2.创建路由对象
let router=new VueRouter({//相关配置
mode:"history",//路由模式
routes:[
{
name:"Example1",
path:"/",
component:()=>import('@/views/Example1.vue'),
},
{
name:"Example2",
path:"/example2",
component:()=>import('@/views/Example2.vue'),
},
{
name:"Example3",
path:"/example3",
component:()=>import('@/views/Example3.vue'),
},
{
name:"Login", //页面自定义名称
path:"/login", //页面路径
component:()=>import('@/views/Login.vue') //导入页面
},
{
name:"Auth",//登录验证页面
path:"/auth",
component:()=>import ('@/views/Auth.vue'),
},
{
name:"Personal",
path:"/personal",
component:()=>import('@/views/Personal.vue'),
meta:{//需要验证登录的页面
auth:true
}
},
{
name:"404",
path:"*",//匹配所有路径
component:()=>import ('@/views/NotFound.vue')
}
]
});
router.beforeEach(function(to,from,next){//导航守卫,验证登录
if(to.meta.auth){
if(store.state.loginUser.isLogin){
next({
name:'Auth',
query:{
nextUrl:to.fullPath
}
});
}else if(store.state.loginUser.data){
next();
}else{
next({name:'Login'});
}
}else{
next();
}
});
//3.导出配置,在main.js配置路由到vue实例中
export default router;
路由模式:
1.Hash:路径来自于地址栏中#后面的值,这种兼容性比较好;
2.History:路径来自于真实的地址路劲,旧浏览器不兼容
3.Abstract:路径来自于内存
src/main.js,程序入口设置
import Vue from 'vue';
import App from './App.vue';
import './assets/css/global.css';
import router from "./router/index.js"; //引入路由
import store from "./store/index.js"; //引入状态管理
Vue.config.productionTip = false;
//获取登录数据
store.dispatch("loginUser/getUserInfo");
new Vue({
render: h => h(App),
router,
store
}).$mount('#app');
src/APP.vue,配置路由出入口
<template>
<div id="app">
<header>
<div class="container">
<div class="title">
SpingBoot+Vue+Three.js
</div>
<ul class="nav">
<li v-for="item of nav" :key="item.id">
<!-- 命名导航-->
<router-link :to="{name:item.url}">{{item.name}}</router-link>
</li>
</ul>
<div class="user">
<template v-if="userInfo">
<router-link :to="{name:'Personal'}" class="a-link">用户:{{userInfo.username}}</router-link>
<a href="" @click.prevent="logout()" class="a-link">注销</a>
</template>
<template v-else>
<router-link :to="{name:'Login'}" class="a-link">登录</router-link>
</template>
</div>
</div>
</header>
<!-- 路由的出入口,该标签会根据不同的访问路径,渲染不同的组件-->
<router-view></router-view>
</div>
</template>
<script>
import {mapState} from 'vuex';
export default {
name: 'App',
components: {
},
data(){
return{
nav:[
{
id:"001",
name:"three.js案例一",
url:"Example1"
},
{
id:"002",
name:"three.js案例二",
url:"Example2"
},
{
id:"003",
name:"three.js案例三",
url:"Example3"
},
]
}
},
computed:mapState("loginUser",{
userInfo:'data'
}),
methods:{
logout(){
this.$store.dispatch("loginUser/logout");
this.$router.push({name:'Login'});
}
}
}
</script>
<style scoped="scoped">
#app{
height: 100%;
width: 100%;
}
header{
height: 60px;
background: #000;
color:#fff;
position: fixed;
z-index: 100;
width: 100%;
border-bottom: 1px solid #fff;
display: flex;
justify-content: center;
}
.container{
display: flex;
width: 80%;
}
.title{
display: flex;
height: 100%;
align-items: center;
font-size: 25px;
}
.nav{
display: flex;
align-items: center;
margin: 0 60px;
width: 700px;
list-style: none;
}
.nav li{
padding: 0 30px;
}
.router-link-exact-active{
color: #fcb85f;
}
.a-link{
margin-left: 10px;
color:#fff;
font-size: 13px;
}
.user{
display: flex;
align-items: center;
}
</style>
②设置请求服务
src/service/userService.js,用户登录请求服务
import axios from 'axios';
//登录
async function login(userInfo){
//post方法获取登录信息
let resp=await axios.post('http://127.0.0.1:8089/springboot_vue/loginCheck',userInfo);
//获取服务器授权码
let token=resp.headers.authorization;
if(token){
localStorage.setItem("token",token);
}
return resp.data;
}
//注销
function logout(){
localStorage.removeItem("token");
}
//使用保存的令牌从服务器获取登录信息
async function getUserInfo(){
let token=localStorage.getItem("token");
if(token){
let resp=await axios.get("http://127.0.0.1:8089/springboot_vue/getUserInfo",{
headers:{
authorization:`${token}`
}
});
return resp.data.data;
}else{
return null;
}
}
export {
login,
logout,
getUserInfo
}
③配置状态管理
src/store/index.js,状态管理基本配置
import Vue from 'vue';
import vuex from 'vuex';
import loginUser from './loginUser.js';//引入用户登录信息配置
//1.安装
Vue.use(vuex);
//2.创建vuex的状态管理对象
let store=new vuex.Store({//配置
modules:{
loginUser,
}
});
//3.导出配置,在main.js注入到vue实例中
export default store;
src/store/loginUser.js,登录用户状态管理
import {login,logout,getUserInfo} from '../service/userService.js';
export default{
namespaced:true,//开启命名空间
state:{
isLogin:false,//是否正在登录
data:null//登录用户信息
},
mutations:{
setData(state,payload){
state.data=payload;
},
setIsLogin(state,payload){
state.isLogin=payload;
}
},
actions:{
async login(context,payload){
context.commit('setIsLogin',true);
let resp=await login(payload);
let result=false;
if(resp.code===0){//登录成功
context.commit('setData',resp.data);
result=true;
}
context.commit('setIsLogin',false);
return result;
},
logout(context){
logout();
context.commit('setData',null);
},
async getUserInfo(context){
context.commit('setIsLogin',true);
let resp=await getUserInfo();
context.commit('setData',resp);
context.commit('setIsLogin',false);
}
}
}
④基本页面
src/view/Auth.vue,登录验证页面
<template>
<Center>
<h1>登录验证中...</h1>
</Center>
</template>
<script>
import Center from "../components/Center.vue";
import {mapState} from "vuex";
export default{
components:{
Center
},
computed:mapState("loginUser",["data","isLogin"]),
methods:{
handleLogin(){
if(this.isLogin){
return;
}
if(this.data){
if(this.$route.query.nextUrl){
this.$router.push(this.$route.query.nextUrl);
}else{
this.$router.push({name:"Personal"});
}
}else{
this.$router.push({name:"Login"});
}
}
},
watch:{
isLogin:{
immediate:true,
handler(){
this.handleLogin();
}
},
}
}
</script>
<style>
</style>
使用watch的注意事项:1.当监听的数据不是一个简单的基本类型,比如一个对象,一个数组,此时应该使用深度监听:deep:true;2.当想让监听器一启动就触发一次watch,应该使用: immediate: true。
src/view/Login.vue,登录页面
<template>
<Center>
<h2>登录页面Login.vue</h2>
<form class="login-container" @submit.prevent="handleSubmit()">
<div class="form-item">
<div class="input">
<label>账号:</label>
<input type="text" v-model="userInfo.username" @input="validateEmpty('username','请输入用户名')"/>
</div>
<FormError :msg="errorInfo.username"></FormError>
</div>
<div class="form-item">
<div class="input">
<label>密码:</label>
<input type="password" v-model="userInfo.password" @input="validateEmpty('password','请输入密码')"/>
</div>
<FormError :msg="errorInfo.password"></FormError>
</div>
<div class="form-item">
<div class="input">
<label></label>
<button>{{$store.state.loginUser.isLogin ? '登陆中...' : '登录'}}</button>
</div>
<FormError :msg="errorInfo.server" :isCenter="true"></FormError>
</div>
</form>
</Center>
</template>
<script>
import Center from '../components/Center.vue';
import FormError from '../components/FormError.vue';
import axios from 'axios';
export default{
name:'Login',
components:{
Center,
FormError
},
data(){
return{
userInfo:{
username:"",
password:""
},
errorInfo:{
username:"",
password:"",
server:""
}
}
},
methods:{
validateEmpty(field,msg){//输入非空验证,field元素名,msg错误信息
if(this.userInfo[field]){
this.errorInfo[field]="";
return true;
}else{
this.errorInfo[field]=msg;
return false;
}
},
async handleSubmit(){
if(
this.validateEmpty('username','请输入用户名')
&& this.validateEmpty('password','请输入密码')
){
let result=await this.$store.dispatch('loginUser/login',this.userInfo);
if(result){
alert("登录成功!");
this.$router.push({name:"Personal"})
}else{
this.errorInfo.server="用户名或密码错误";
}
}
}
}
}
</script>
<style scoped="scoped">
.login-container{
margin-top: 50px;
width: 400px;
}
.input{
display: flex;
}
label{
width: 56px;
display: inline-block;
font-size: 18px;
line-height: 40px;
}
input,button{
border: 1px solid #ccc;
flex-grow: 1;
border-radius: 5px;
}
button{
font-size:16px;
background-color: #409EFF;
color:#FFFFFF;
line-height: 40px;
}
</style>
登录页面