网站建设流程怎么样,网页制作基础教程背景图片,网站图片设置,个人单页网站初接触vue的时候觉得vue好难#xff0c;因为项目中要用到#xff0c;就硬着头皮上#xff0c;慢慢的发现也不难#xff0c;无外乎画个布局#xff0c;然后通过样式调整界面。在通过属性和方法跟js交互。js就和我们写的java代码差不多了#xff0c;复杂一点的就是引用这种…初接触vue的时候觉得vue好难因为项目中要用到就硬着头皮上慢慢的发现也不难无外乎画个布局然后通过样式调整界面。在通过属性和方法跟js交互。js就和我们写的java代码差不多了复杂一点的就是引用这种那种库然后就能做出来一个界面了。如果你的项目就是和服务器交互感觉用vue来做确实也蛮合适的。
在上手之前我先说下我们要实现的场景。我们需要做一个注册登陆的功能相关字段只有用户名密码昵称注册之后就能登陆相关的后端逻辑我会在另外一篇文章提到这里只需要关心前端逻辑我们需要实现的功能有
注册页面登陆页面注册后保存用户名密码到本地登陆页面取本地用户名密码填充点击按钮登录并根据返回跳转国际化
Get Start
使用HbuildX创建一个Vue2的项目什么模板都不选就最基础的那种。创建完之后参考一下我的目录结果吧缺失的文件补一下 本来要新创建一个vue页面的我为了省事直接修改了index.vue在里面添加了登陆界面注册界面通过登陆界面的注册按钮打开。
我们先在pages.json把页面名自定义一下默认是uni-app我们改成用户登录。同时我添加了用户注册的页面并在对应的位置创建了Vue文件。
{pages: [ //pages数组中第一项表示应用启动页参考https://uniapp.dcloud.io/collocation/pages{path: pages/index/index,style: {navigationBarTitleText: 用户登录//修改标题为用户登录标题颜色也可以像下面一样配置}},{path: pages/register/register,style: {navigationBarTitleText: 用户注册}}],globalStyle: {navigationBarTextStyle: black,navigationBarTitleText: 登录Demo,// 通用标题navigationBarBackgroundColor: #F8F8F8,backgroundColor: #F8F8F8},uniIdRouter: {}
}
引入网络请求库luch-request。这个类比较长这里就不贴出来了大家可以去这里下载 也可以按照她开发者文档上说的去配置我是下过来使用的。我们来实现登陆界面
templateview classcontainerview classleft-bottom-sign/viewview classback-btn yticon icon-zuojiantou-up clicknavBack/viewview classright-top-sign/view!-- 设置白色背景防止软键盘把下部绝对定位元素顶上来盖住输入框等 --view classwrapperview classleft-top-sign{{$t(vue.public.login)}}/viewview classwelcome{{$t(vue.public.welcomeback)}}/viewview classinput-contentview classinput-itemtext classtit{{$t(vue.public.username)}}/textinput typetext v-modelusername maxlength11//viewview classinput-itemtext classtit{{$t(vue.public.pwd)}}/textinput typetext v-modelpassword placeholder-classinput-empty maxlength20password confirmtoLogin //view/viewbutton classconfirm-btn clicktoLogin :disabledlogining{{$t(vue.public.tologin)}}/buttonview classforget-section clicktoRegist{{$t(vue.public.forgetpwd)}}/view/viewview classregister-section{{$t(vue.public.notaccount)}}text clicktoRegist{{$t(vue.public.registernow)}}/text/view/view
/templatescriptimport {mapMutations} from vuex;import {memberLogin,memberInfo} from /api/member.js;export default {data() {return {username: ,password: ,logining: false}},onLoad() {this.username uni.getStorageSync(username) || ;this.password uni.getStorageSync(password) || ;},methods: {...mapMutations([login]),navBack() {uni.navigateBack();},toRegist() {uni.navigateTo({url:/pages/public/register});},async toLogin() {this.logining true;memberLogin({username: this.username,password: this.password}).then(response {let token response.data.tokenHeadresponse.data.token;uni.setStorageSync(token,token);uni.setStorageSync(username,this.username);uni.setStorageSync(password,this.password);memberInfo().then(response{this.login(response.data);uni.navigateTo({url:/pages/user/user});});}).catch(() {this.logining false;});},},}
/scriptstyle langscsspage {background: #fff;}.container {padding-top: 115px;position: relative;width: 100vw;height: 100vh;overflow: hidden;background: #fff;}.wrapper {position: relative;z-index: 90;background: #fff;padding-bottom: 40upx;}.back-btn {position: absolute;left: 40upx;z-index: 9999;padding-top: var(--status-bar-height);top: 40upx;font-size: 40upx;color: $font-color-dark;}.left-top-sign {font-size: 120upx;color: $page-color-base;position: relative;left: -16upx;}.right-top-sign {position: absolute;top: 80upx;right: -30upx;z-index: 95;:before,:after {display: block;content: ;width: 400upx;height: 80upx;background: #b4f3e2;}:before {transform: rotate(50deg);border-radius: 0 50px 0 0;}:after {position: absolute;right: -198upx;top: 0;transform: rotate(-50deg);border-radius: 50px 0 0 0;/* background: pink; */}}.left-bottom-sign {position: absolute;left: -270upx;bottom: -320upx;border: 100upx solid #d0d1fd;border-radius: 50%;padding: 180upx;}.welcome {position: relative;left: 50upx;top: -90upx;font-size: 46upx;color: #555;text-shadow: 1px 0px 1px rgba(0, 0, 0, .3);}.input-content {padding: 0 60upx;}.input-item {display: flex;flex-direction: column;align-items: flex-start;justify-content: center;padding: 0 30upx;background: $page-color-light;height: 120upx;border-radius: 4px;margin-bottom: 50upx;:last-child {margin-bottom: 0;}.tit {height: 50upx;line-height: 56upx;font-size: $font-sm2upx;color: $font-color-base;}input {height: 60upx;font-size: $font-base 2upx;color: $font-color-dark;width: 100%;}}.confirm-btn {width: 630upx;height: 76upx;line-height: 76upx;border-radius: 50px;margin-top: 70upx;background: $uni-color-primary;color: #fff;font-size: $font-lg;:after {border-radius: 100px;}}.confirm-btn2 {width: 630upx;height: 76upx;line-height: 76upx;border-radius: 50px;margin-top: 40upx;background: $uni-color-primary;color: #fff;font-size: $font-lg;:after {border-radius: 100px;}}.forget-section {font-size: $font-sm2upx;color: $font-color-spec;text-align: center;margin-top: 40upx;}.register-section {position: absolute;left: 0;bottom: 50upx;width: 100%;font-size: $font-sm2upx;color: $font-color-base;text-align: center;text {color: $font-color-spec;margin-left: 10upx;}}
/style
接着我们在主js中引入我们添加的依赖以便于全局生效。 main.js:
import Vue from vue
import store from ./store
import App from ./App
import i18n from ./localeconst msg (title, duration1500, maskfalse, iconnone){//统一提示方便全局修改if(Boolean(title) false){return;}uni.showToast({title,duration,mask,icon});
}const prePage (){let pages getCurrentPages();let prePage pages[pages.length - 2];// #ifdef H5return prePage;// #endifreturn prePage.$vm;
}Vue.config.productionTip false
Vue.prototype.$fire new Vue();
Vue.prototype.$store store;
Vue.prototype.$api {msg, prePage};App.mpType appconst app new Vue({i18n,...App
})
app.$mount()我们可以看到main.js引入了vuw的脚本本地化的脚本(store/index.js)以及国际化脚本(locale/index.js)。Vue的脚本这里你可以要可以不要我就写了一个界面的日志跟踪:
scriptexport default {onLaunch: function() {console.log(App Launch)},onShow: function() {console.log(App Show)},onHide: function() {console.log(App Hide)}}
/scriptstyle/*每个页面公共css */
/style
然后再store这里通过mutations定义了两个常量方法一个是登录一个是登出这两个方法通过调用vue的store管理方法来存储登陆状态和登录信息。mutations表示常量类似java中的static。
import Vue from vue
import Vuex from vuexVue.use(Vuex)const store new Vuex.Store({state: {hasLogin: false,userInfo: {},},mutations: {login(state, provider) {state.hasLogin true;state.userInfo provider;uni.setStorage({//缓存用户登陆状态key: userInfo, data: provider }) console.log(state.userInfo);},logout(state) {state.hasLogin false;state.userInfo {};uni.removeStorage({ key: userInfo });uni.removeStorage({key: token })}},actions: {}
})export default store
然后我们把locale的内容也补充一下因为再login.vue中引用到了国际化的字符串。当然了我们也可以再page中也进行国际化。vue官方支持国家话方案可以参考这里。 locale/index.js
import Vue from vue;
import VueI18n from vue-i18n
import en from ./en.json
import zh from ./zh.json
Vue.use(VueI18n); // 全局注册国际化包// 准备翻译的语言环境信息
const i18n new VueI18n({locale: zn, // 初始化中文messages: {zn:zh,en:en}
});
export default i18n
国际化的文案分别放在各个国家的json中比如zh.json
{vue.public.login: LOGIN,vue.public.welcomeback: 欢迎回来,vue.public.welcomeregister: 欢迎注册,vue.public.username: 用户名,vue.public.nickname: 昵称,vue.public.inputusername: 请输入用户名,vue.public.inputnickname: 请输入昵称,vue.public.pwd: 密码,vue.public.inputpwdhint: 8-18位不含特殊字符的数字、字母组合,vue.public.tologin: 登录,vue.public.alreadyRegister: 已有账号?,vue.public.loginnow: 前往登录,vue.public.toregister: 注册,vue.public.testlogin: 获取体验账号,vue.public.forgetpwd: 忘记密码?,vue.public.notaccount: 还没有账号?,vue.public.registernow: 马上注册
}英文的国家化和其他的国际化都是使用上述json格式只不过冒号后面的值不一样而已。到这里界面已经写好了虽然还不能做网络请求至少我们可以看看效果了。再看效果之前我们需要再项目的根目录打开终端输入npm install 也可以加上-t查看安装进度。然后可以使用npm run dev或者使用HbuildX提供的运行按钮来运行到内置浏览器或Chrome
注册界面也写一下
templateview classcontainerview classleft-bottom-sign/viewview classback-btn yticon icon-zuojiantou-up clicknavBack/viewview classright-top-sign/view!-- 设置白色背景防止软键盘把下部绝对定位元素顶上来盖住输入框等 --view classwrapperview classleft-top-sign{{$t(vue.public.login)}}/viewview classwelcome{{$t(vue.public.welcomeregister)}}/viewview classinput-contentview classinput-itemtext classtit{{$t(vue.public.username)}}/textinput typetext v-modelusername :placeholder$t(vue.public.inputusername) maxlength11//viewview classinput-itemtext classtit{{$t(vue.public.nickname)}}/textinput typetext v-modelnickname :placeholder$t(vue.public.inputnickname) maxlength11//viewview classinput-itemtext classtit{{$t(vue.public.pwd)}}/textinput typetext v-modelpassword :placeholder$t(vue.public.inputpwdhint) placeholder-classinput-empty maxlength20password //view/viewbutton classconfirm-btn clicktoRegister {{$t(vue.public.toregister)}}/button/viewview classregister-section{{$t(vue.public.alreadyRegister)}}text clicktoLogin{{$t(vue.public.loginnow)}}/text/view/view
/templatescriptimport {mapMutations} from vuex;import {memberLogin,memberInfo, memberRegister} from /api/member.js;export default {data() {return {username: ,nickname: ,password: ,}},methods: {...mapMutations([login]),navBack() {uni.navigateBack();},toLogin() {uni.navigateTo({url:/pages/public/login});},async toRegister() {memberRegister({username: this.username,nickname: this.nickname,password: this.password}).then(response {//this.toLogin();console.log(response);if(response.code 200){uni.showToast({title:Register Success.,duration:1500});setTimeout(this.toLogin, 2000);}}).catch(() {});},},}
/scriptstyle langscsspage {background: #fff;}.container {padding-top: 115px;position: relative;width: 100vw;height: 100vh;overflow: hidden;background: #fff;}.wrapper {position: relative;z-index: 90;background: #fff;padding-bottom: 40upx;}.back-btn {position: absolute;left: 40upx;z-index: 9999;padding-top: var(--status-bar-height);top: 40upx;font-size: 40upx;color: $font-color-dark;}.left-top-sign {font-size: 120upx;color: $page-color-base;position: relative;left: -16upx;}.right-top-sign {position: absolute;top: 80upx;right: -30upx;z-index: 95;:before,:after {display: block;content: ;width: 400upx;height: 80upx;background: #b4f3e2;}:before {transform: rotate(50deg);border-radius: 0 50px 0 0;}:after {position: absolute;right: -198upx;top: 0;transform: rotate(-50deg);border-radius: 50px 0 0 0;/* background: pink; */}}.left-bottom-sign {position: absolute;left: -270upx;bottom: -320upx;border: 100upx solid #d0d1fd;border-radius: 50%;padding: 180upx;}.welcome {position: relative;left: 50upx;top: -90upx;font-size: 46upx;color: #555;text-shadow: 1px 0px 1px rgba(0, 0, 0, .3);}.input-content {padding: 0 60upx;}.input-item {display: flex;flex-direction: column;align-items: flex-start;justify-content: center;padding: 0 30upx;background: $page-color-light;height: 120upx;border-radius: 4px;margin-bottom: 50upx;:last-child {margin-bottom: 0;}.tit {height: 50upx;line-height: 56upx;font-size: $font-sm2upx;color: $font-color-base;}input {height: 60upx;font-size: $font-base 2upx;color: $font-color-dark;width: 100%;}}.confirm-btn {width: 630upx;height: 76upx;line-height: 76upx;border-radius: 50px;margin-top: 70upx;background: $uni-color-primary;color: #fff;font-size: $font-lg;:after {border-radius: 100px;}}.confirm-btn2 {width: 630upx;height: 76upx;line-height: 76upx;border-radius: 50px;margin-top: 40upx;background: $uni-color-primary;color: #fff;font-size: $font-lg;:after {border-radius: 100px;}}.forget-section {font-size: $font-sm2upx;color: $font-color-spec;text-align: center;margin-top: 40upx;}.register-section {position: absolute;left: 0;bottom: 50upx;width: 100%;font-size: $font-sm2upx;color: $font-color-base;text-align: center;text {color: $font-color-spec;margin-left: 10upx;}}
/style
登陆页面和注册页面写好了我们要来实现网络请求在请求之前先做一个配置主要是服务器和拦截器的设置拦截器有利于我们跟踪代码运行requestUtil.js
import Request from /js_sdk/luch-request/request.js
import i18n from ../locale;const http new Request()http.setConfig((config) { /* 设置全局配置 */config.baseUrl http://127.0.0.1:8902 /* 根域名不同 */config.header {...config.header}return config
})/*** 自定义验证器如果返回true 则进入响应拦截器的响应成功函数(resolve)否则进入响应拦截器的响应错误函数(reject)* param { Number } statusCode - 请求响应体statusCode只读* return { Boolean } 如果为true,则 resolve, 否则 reject*/
http.validateStatus (statusCode) {return statusCode 200
}http.interceptor.request((config, cancel) { /* 请求之前拦截器 */const token uni.getStorageSync(token);if(token){config.header {Authorization:token,...config.header}}else{config.header {...config.header}}/*if (!token) { // 如果token不存在调用cancel 会取消本次请求但是该函数的catch() 仍会执行cancel(token 不存在) // 接收一个参数会传给catch((err) {}) err.errMsg token 不存在}*/return config
})http.interceptor.response((response) { /* 请求之后拦截器 */const res response.data;if (res.code ! 200) {//提示错误信息uni.showToast({title:res.message,duration:1500})//401未登录处理if (res.code 401) {uni.showModal({title: i18n.t(vue.request.permit), //提示content:i18n.t(vue.request.permithint), //你已被登出可以取消继续留在该页面或者重新登录,confirmText:i18n.t(vue.request.relogin), //重新登录,cancelText:i18n.t(vue.request.cancel), //取消,success: function(res) {if (res.confirm) {uni.navigateTo({url: /pages/public/login})} else if (res.cancel) {console.log(用户点击取消);}}});}return Promise.reject(response);} else {return response.data;}
}, (response) {//提示错误信息console.log(response error, JSON.stringify(response));uni.showToast({title:response.errMsg,duration:1500})return Promise.reject(response);
})export function request (options {}) {return http.request(options);
}export default request上面的vue页面我们再注册调用了注册方法memberRegister,再登录调用了memberLogin登陆方法。我们把这个功能实现下api/member.js
import request from /utils/requestUtilexport function memberLogin(data) {return request({method: POST,url: /sso/login,header: {content-type: application/x-www-form-urlencoded;charsetutf-8},data: data})
}export function memberRegister(data) {return request({method: POST,url: /sso/register,header: {content-type: application/x-www-form-urlencoded;charsetutf-8},data: data})
}export function memberInfo() {return request({method: GET,url: /sso/info})
}
到这里我们前端页面的注册登陆就写好了你可以配合服务端来测试。