官网

新建默认模板项目

1、下载安装

使用下载的方式安装,能更方便阅读源码,但是每次升级都需要重新下载并覆盖uview-ui文件夹。

  • 在uni-app插件市场右上角选择使用HBuilder X 导入插件或者下载插件ZIP
  • 如果您的项目是由HBuilder X创建的标准uni-app项目,将下载后的uview-ui文件夹,复制到项目根目录。
  • 如果您的项目是由vue-cli模式创建的, 请将下载后的uview-ui文件夹放到项目的src文件夹中即可。

注意: 此安装方式必须要按照下载方式安装的配置中的说明配置了才可用。

2、配置

由于uView支持npm下载的方式安装,二者配置几乎一致,因为某些平台的兼容性,在配置easycom稍有不同,为了不造成混淆,这里将两种 方式分开说明:

我用的下载方式
uView依赖SCSS;

具体配置

配置步骤

2-1. 引入uView主JS库

在项目根目录中的main.js中,引入并使用uView的JS库,注意这两行要放在import Vue之后。

// main.js
import uView from "uview-ui";
Vue.use(uView);

2-2、.在引入uView的全局SCSS主题文件

在项目根目录的uni.scss中引入此文件。

/* uni.scss */
@import 'uview-ui/theme.scss';

2-3. 引入uView基础样式

注意:在App.vue中首行的位置引入,注意给style标签加入lang="scss"属性

<style lang="scss">
	/* 注意要写在第一行,同时给style标签加入lang="scss"属性 */
	@import "uview-ui/index.scss";
</style>

2-4、 配置easycom组件模式

此配置需要在项目根目录的pages.json中进行。

tips:

  1. uni-app为了调试性能的原因,修改easycom规则不会实时生效,配置完后,您需要重启HX或者重新编译项目才能正常使用uView的功能。
  2. 请确保您的pages.json中只有一个easycom字段,否则请自行合并多个引入规则。
// pages.json
{
	"easycom": {
		"^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue"
	},
	
	// 此为本身已有的内容
	"pages": [
		// ......
	]
}

在pages/index/index中引入组件展示

 3、使用阿里图标库

在阿里图标库新建项目,加入图标,修改设置

  1. 复制"iconfont.css"文件到uni-app目根目录的static目录后(也可以为其他目录),打开"iconfont.css",内部如下:

删掉下图圈出的部分,记得把"src: url('data:application/x-font-woff2......"最后的逗号,改成分号;

  1. 最终如下图:

在项目根目录的"App.vue"中,引入上述的"iconfont.css",注意自己存放的路径,且通过"@import"引入的外部样式,为了兼容性建议使用相对路径, 且引入的样式,需要写在style标签有效内容中的最前面,如下

<style lang="scss">
	/*每个页面公共css */
	@import "uview-ui/index.scss";
	@import "./static/css/iconfont.css";
	page{
		width: 100vw;
		height: calc(100% - var(--status-bar-height));
		display: flex;
		flex-direction: column;
		box-sizing: border-box;
		view{
			box-sizing: border-box;
		}
		.form{
			box-sizing: border-box;
		}
	}
</style>

 如上图,我们得到"backspace"值,使用如下:
 

<u-icon name="backspace" custom-prefix="custom-icon" size="30" color="#888888"></u-icon>

 从上可以看出,相比uView内置的图标使用,多了一句固定的custom-prefix="custom-icon",其余使用方法完全相同

注意:执行完上面的操作后,您就可以随心所欲的扩展自己的图标了,最重要的是第二步,修改了它,就免了以后每次都要修改"iconfont.css"的多处细节。 当然,每次新增图标,当您把"iconfont.css"复制至项目中覆盖原来的"iconfont.css"后,都需要执行一遍第5步删掉多余的内容,别忘了修改最后的,;

最后提一下,为了多平台兼容性,您应该仅把单色图标添加到阿里图标库的项目中,即使添加了多色的图标,在使用中,也会被转成单色。

4、封装请求函数

根目录下新建common文件夹,在common文件夹下新建utils文件夹,在utils文件夹下新建http.interceptor.js

// /common/http.interceptor.js

let num=0
// 这里的vm,就是我们在vue文件里面的this,所以我们能在这里获取vuex的变量,比如存放在里面的token变量
const install = (Vue, vm) => {
	// 此为自定义配置参数,具体参数见上方说明
	Vue.prototype.$u.http.setConfig({
		// #ifdef  H5
			baseUrl: 'http://********/app-api',
		// #endif
		// #ifdef  MP-WEIXIN
			baseUrl: 'http://*******/app-api',
		// #endif
		method: 'POST',
		// 设置为json,返回后会对数据进行一次JSON.parse()
		dataType: 'json',
		showLoading: false, // 是否显示请求中的loading
		//loadingText: 'jiaziahzong...', // 请求loading中的文字提示
		//loadingTime: 800, // 在此时间内,请求还没回来的话,就显示加载中动画,单位ms
		originalData: false, // 是否在拦截器中返回服务端的原始数据
		loadingMask: true, // 展示loading的时候,是否给一个透明的蒙层,防止触摸穿透
		// 配置请求头信息
		header: {
			'content-type': 'application/json;charset=UTF-8'
		},
		// ......
	});
	
	// 请求拦截,配置Token等参数
	Vue.prototype.$u.http.interceptor.request = (config) => {
		console.log('77')
		uni.showLoading({
			title:'加载中'
		})
		num++
		// 引用token
		// 方式一,存放在vuex的token,假设使用了uView封装的vuex方式
		// 见:https://uviewui.com/components/globalVariable.html
		// config.header.token = vm.token;
		
		// 方式二,如果没有使用uView封装的vuex方法,那么需要使用$store.state获取
		// config.header.token = vm.$store.state.token;
		
		// 方式三,如果token放在了globalData,通过getApp().globalData获取
		// config.header.token = getApp().globalData.username;
		
		// 方式四,如果token放在了Storage本地存储中,拦截是每次请求都执行的
		// 所以哪怕您重新登录修改了Storage,下一次的请求将会是最新值
		 const token = uni.getStorageSync('token');
		 config.header.token = token?token:'';
		//config.header.token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJhZG1pbiIsInN1YiI6IjIwQzA4M0M0QzJERTZEQUE3NzFERkQxMEQzMkQwMTI3IiwiZXhwIjoxNjE5Njc1MDUzfQ.utqHnA6niLv5gPOis7kqac7IcrqYh7otTGBD1NTgQGc';
		
		// 可以对某个url进行特别处理,此url参数为this.$u.get(url)中的url值
		if(config.url == '/login/login') config.header.noToken = true;
		// 最后需要将config进行return
		return config;
		// 如果return一个false值,则会取消本次请求
		// if(config.url == '/user/rest') return false; // 取消某次请求
	}
	// 响应拦截,判断状态码是否通过
	Vue.prototype.$u.http.interceptor.response = (res) => {
		num--;
		if (num <= 0) {
		      uni.hideLoading()
		    } else {
		     uni.showLoading({
		     	title:'加载中'
		     })  
		    }
		if(res.code == 1) {
			// res为服务端返回值,可能有code,result等字段
			// 这里对res.result进行返回,将会在this.$u.post(url).then(res => {})的then回调中的res的到
			// 如果配置了originalData为true,请留意这里的返回值
			return res.data;
		} else if(res.code == 201) {
			
			// 假设201为token失效,这里跳转登录
			vm.$u.toast('验证失败,请重新登录');
			setTimeout(() => {
				// 此为uView的方法,详见路由相关文档
				vm.$u.route('/pages/login/login')
			}, 1500)
			return false;
		} else {
			// 如果返回false,则会调用Promise的reject回调,
			// 并将进入this.$u.post(url).then().catch(res=>{})的catch回调中,res为服务端的返回值
			return res;
			// uni.showToast({
			// 	icon:'none',
			// 	title:res.message
			// })
		}
	}
}

export default {
	install
}

在main.js中引入http.interceptor.js

import Vue from 'vue'
import App from './App'
import store from './store/index.js'
Vue.config.productionTip = false
import uView from "uview-ui";
Vue.use(uView);
App.mpType = 'app'

const app = new Vue({
	store,
    ...App
})
// http拦截器,将此部分放在new Vue()和app.$mount()之间,才能App.vue中正常使用
import httpInterceptor from '@/common/utils/http.interceptor.js'
Vue.use(httpInterceptor, app)

// http接口API集中管理引入部分
import httpApi from '@/common/api/index.js'
Vue.use(httpApi, app)

app.$mount()

5、分模块统一管理api

在common文件夹下新建api文件夹,在api文件夹下新建modules文件夹和index.js

home.js

import Vue from "vue"
function getHomeData(data = {}) {
   return Vue.prototype.$u.post('/admin/goods-service/load-goods-service-type-list',data)
}
function getHomeData1(data = {}) {
   return Vue.prototype.$u.post('/sys/admin/login',data)
}

export default {
  getHomeData,
  getHomeData1
};

user.js

// /common/http.api.js
// 如果没有通过拦截器配置域名的话,可以在这里写上完整的URL(加上域名部分)
// let hotSearchUrl = '/ebapi/store_api/hot_search';
// let indexUrl = '/ebapi/public_api/index';

// 此处第二个参数vm,就是我们在页面使用的this,你可以通过vm获取vuex等操作,更多内容详见uView对拦截器的介绍部分:
// https://uviewui.com/js/http.html#%E4%BD%95%E8%B0%93%E8%AF%B7%E6%B1%82%E6%8B%A6%E6%88%AA%EF%BC%9F
// const install = (Vue, vm) => {

	
// 	// 此处使用了传入的params参数,一切自定义即可
// 	let getData = (params = {}) => vm.$u.post("/admin/goods-service/load-goods-service-list-with-type", params);
	
// 	// 将各个定义的接口名称,统一放进对象挂载到vm.$u.api(因为vm就是this,也即this.$u.api)下
// 	vm.$u.api = {getData};
// }

// export default {
// 	install
// }
import Vue from "vue"
function Login(data = {}) {
   return Vue.prototype.$u.post('/api/user/login',data)
}
function getUserData1(data = {}) {
   return Vue.prototype.$u.post('/sys/admin/login',data)
}

export default {
  Login,
  getUserData1
};

index.js(一起导出)

const modulesFiles = require.context('./modules', true, /\.js$/)
console.log(modulesFiles.keys(),'1111')
// you do not need `import app from './modules/app'`
// it will auto require all vuex module from modules file
let functions={};//
modulesFiles.keys().reduce((modules, modulePath) => {

  // set './app.js' => 'app'
  const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
  const value = modulesFiles(modulePath)
  //modules[moduleName] = value.default
  functions={...value.default,...functions}
  
}, {})
console.log(functions,'灌灌灌灌')
const install = (Vue, vm) => {
	// 此处使用了传入的params参数,一切自定义即可
	//let getData = (params = {}) => vm.$u.post("/admin/goods-service/load-goods-service-list-with-type", params);
	
	// 将各个定义的接口名称,统一放进对象挂载到vm.$u.api(因为vm就是this,也即this.$u.api)下
	vm.$u.api = {...functions};
}

export default {
	install
}

在main.js中导入

import Vue from 'vue'
import App from './App'
import store from './store/index.js'
Vue.config.productionTip = false
import uView from "uview-ui";
Vue.use(uView);
App.mpType = 'app'

const app = new Vue({
	store,
    ...App
})
// http拦截器,将此部分放在new Vue()和app.$mount()之间,才能App.vue中正常使用
import httpInterceptor from '@/common/utils/http.interceptor.js'
Vue.use(httpInterceptor, app)

// http接口API集中管理引入部分
import httpApi from '@/common/api/index.js'
Vue.use(httpApi, app)

app.$mount()

5、状态管理

modules下的user.js

import Vue from 'vue'
const state = {
  userInfo:'',
  token:'',    //系统标志
}

const mutations = {
  SET_USERINFO: (state,userInfo) => {
    state.userInfo = userInfo;
	uni.setStorageSync('userInfo',userInfo)
  },
  SET_TOKEN: (state, token) => {
    state.token = token;
	uni.setStorageSync('token',token)
  },
}

const actions = {
  // user login
  login({ commit }, userInfo) {
    const { username, password } = userInfo;
	return new Promise(async (resolve,reject)=>{
		let res = await this.$u.api.Login({ username: username.trim(), password: password })
		  console.log(res,'登录')
		  if(res){
			  commit('SET_USERINFO', JSON.stringify(res));
			  commit('SET_TOKEN', res.token);
			  resolve(res)
		  }else{
			  reject()
		  }
		  
	})
  },
  // user logout
  logout({ commit, state }) {
    return new Promise((resolve, reject) => {
      logout({ token: state.token}).then((res) => {
        if (res.code ===1) {

          commit('SET_TOKEN', '')
          removeToken()
          resolve(res)
        } else{
          reject()
        }
      }).catch(error => {
        reject(error)
      })
    })
  },
  
  // remove token
  resetToken({ commit }) {
    return new Promise(resolve => {
      commit('SET_TOKEN', '')
      commit('SET_PAGE', [])
      removeToken()
      resolve()
    })
  },
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

getters.js

const getters = {
  token: state => state.user.token,
  userInfo: state => state.user.userInfo,
}
export default getters

index.js(统一导出)

import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
import user from './modules/user'


Vue.use(Vuex)

const store = new Vuex.Store({
  modules: {
    user,
  },
  getters
})

export default store

在main.js中导入

import Vue from 'vue'
import App from './App'
import store from './store/index.js'
Vue.config.productionTip = false
import uView from "uview-ui";
Vue.use(uView);
App.mpType = 'app'

const app = new Vue({
	store,
    ...App
})
// http拦截器,将此部分放在new Vue()和app.$mount()之间,才能App.vue中正常使用
import httpInterceptor from '@/common/utils/http.interceptor.js'
Vue.use(httpInterceptor, app)

// http接口API集中管理引入部分
import httpApi from '@/common/api/index.js'
Vue.use(httpApi, app)

app.$mount()

6、登录页

login.vue

<template>
	<view class="login">
		<u-form class="form" :model="form" ref="uForm">
			<u-form-item label="姓名" prop="username"><u-input v-model="form.username" /></u-form-item>
			<u-form-item label="密码" prop="password"><u-input v-model="form.password" /></u-form-item>
			<u-button type="primary" @click="submit">提交</u-button>
		</u-form>
		
	</view>
</template>

<script>
export default {
	data() {
		return {
			form: {
				username: '',
				password: ''
			},
			rules: {
				username: [
					{
						required: true,
						message: '请输入姓名',
						// 可以单个或者同时写两个触发验证方式
						trigger: ['change', 'blur']
					}
				],
				password: [
					{
						required: true,
						message: '请输入密码',
						// 可以单个或者同时写两个触发验证方式
						trigger: ['change', 'blur']
					},
					{
						min: 2,
						message: '密码不能少于2位',
						trigger: 'change'
					}
				]
			}
		};
	},
	// 必须要在onReady生命周期,因为onLoad生命周期组件可能尚未创建完毕
	onReady() {
		this.$refs.uForm.setRules(this.rules);
	},
	methods: {
			submit() {
				this.$refs.uForm.validate(valid => {
					if (valid) {
						this.$store.dispatch('user/login',this.form).then(res=>{
							uni.reLaunch({
								url:'/pages/index/index'
							})
						})
						
					} else {
						console.log('验证失败');
					}
				});
			}
		},
		
};
</script>

<style lang="scss">
	.login{
		height: 100%;
		background-color: $uni-color-primary;
		display: flex;
		flex-direction: column;
		padding:30rpx;
		.form{
			width:100%;
			height: 100%;
			background-color: #fff;
			border-radius: 20rpx;
			padding:30rpx;
		}
	}
</style>

Logo

前往低代码交流专区

更多推荐