uview使用笔记
1、下载安装使用下载的方式安装,能更方便阅读源码,但是每次升级都需要重新下载并覆盖uview-ui文件夹。在uni-app插件市场右上角选择使用HBuilder X 导入插件或者下载插件ZIP如果您的项目是由HBuilder X创建的标准uni-app项目,将下载后的uview-ui文件夹,复制到项目根目录。如果您的项目是由vue-cli模式创建的, 请将下载后的uview-ui文件夹放到项目的s
新建默认模板项目
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:
- uni-app为了调试性能的原因,修改
easycom
规则不会实时生效,配置完后,您需要重启HX或者重新编译项目才能正常使用uView的功能。 - 请确保您的
pages.json
中只有一个easycom
字段,否则请自行合并多个引入规则。
// pages.json
{
"easycom": {
"^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue"
},
// 此为本身已有的内容
"pages": [
// ......
]
}
在pages/index/index中引入组件展示
3、使用阿里图标库
在阿里图标库新建项目,加入图标,修改设置
- 复制"iconfont.css"文件到uni-app目根目录的
static
目录后(也可以为其他目录),打开"iconfont.css",内部如下:
删掉下图圈出的部分,记得把"src: url('data:application/x-font-woff2......"最后的逗号,
改成分号;
。
- 最终如下图:
在项目根目录的"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>
更多推荐
所有评论(0)