uni-app 项目结构

664 阅读10分钟

基本介绍

uniapp 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等多个平台。 具有 vue 和微信小程序的开发经验,可快速上手 uniapp。相对于开发者来说,减少了学习成本,因为学会 uniapp 后,即可开发出 iOS、Android、H5,以及各种小程序的应用,不需要再去学习开发其他应用的框架,相对公司而言,也大大减少了开发成本。

什么是uni-app

uni-app是一个使用Vue.js开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/QQ/钉钉/淘宝)、快应用等多个平台。

为什么要选择uni-app

uni-app在开发者数量、案例、跨端抹平度、扩展灵活性、性能体验、周边生态、学习成本、开发成本等8大关键指标上拥有更强的优势。

怎么用uni-app创建项目

使用HBuilderX创建以uni-ui项目为模板的项目

注意点:

1 创建项目成功之后自助下载一些编译插件(内置终端,scss编译,uni-app编译各端,内置浏览器等等) 2 在下载插件如果出现下载失败或者安装失败的可以将插件的压缩包直接解压到HBuilderX的安装目录下面的plugins下面;如果是使用HBuilder安装插件失败 可以找到安装目录下->update->plugins下面的安装包直接解压到安装目录下->plugins下面即可 image.png

image.png 环境搭建 image.png 安装编辑器 HBuilderX,www.dcloud.io/hbuilderx.h… HBuilderX是通用的前端开发工具,但为uniapp做了特别强化。根据自己电脑,自行下载即可。 项目搭建 image.png image.png 也可以通过命令行创建项目,此处省略,可以参考官方文档学习。 如果是第一次运行小程序需要设置对应的小程序ide的安装路径以及设置小程序的AppId,如下图  image.png 项目运行 image.png 你可以选择运行到各个平台,请自行尝试 注意 如果是第一次运行在微信小程序中,需要做如下设置,不然编译过程会报错 image.png 1、配置微信开发者工具的安装路径 image.png image.png 2、开启端口 image.png 打开微信开发者工具,在左上角菜单栏找到 设置-安全设置,如下图所示开启服务端口 目录结构

使用vue-cli安装项目

<!-- 创建项目 -->
vue create -p dcloudio/uni-preset-vue my-project
<!-- 运行项目 -->
npm run dev:%PLATFORM%
<!-- 打包项目 -->
npm run build:%PLATFORM%

PLATFORM的参考值

平台
app-plusapp平台生成打包资源(支持npm run build:app-plus,可用于持续集成。不支持run,运行调试仍需在HBuilderX中操作)
h5H5
mp-alipay支付宝小程序
mp-baidu百度小程序
mp-weixin微信小程序
mp-toutiao字节跳动小程序
mp-qqqq 小程序
mp-360360 小程序
quickapp-webview快应用(webview)
quickapp-webview-union快应用联盟
quickapp-webview-huawei快应用华为

开发规范

  • 页面文件遵循 Vue 单文件组件 (SFC) 规范
  • 组件标签靠近小程序规范,详见uni-app 组件规范uni-app 组件规范
  • 接口能力(JS API)靠近微信小程序规范,但需将前缀 wx 替换为 uni,详见uni-app接口规范
  • 数据绑定及事件处理同 Vue.js 规范,同时补充了App及页面的生命周期
  • 为兼容多端运行,建议使用flex布局进行开发
  • Tips

  • 编译到任意平台时,static 目录下的文件均会被完整打包进去,且不会编译。非 static 目录下的文件(vue、js、css 等)只有被引用到才会被打包编译进去。
  • static 目录下的 js 文件不会被编译,如果里面有 es6 的代码,不经过转换直接运行,在手机设备上会报错。
  • css、less/scss 等资源不要放在 static 目录下,建议这些公用的资源放在自建的 common 目录下。
  • HbuilderX 1.9.0+ 支持在根目录创建 ext.json、sitemap.json 等小程序需要的文件。

路由

在我的之前的uniapp的项目中有用到两种方式来处理页面路由跳转

  • 使用uni-app官方的api进行路由跳转,然后针对这几个api做一个二次封装模拟路由拦截
  • 使用uni-simple-router来做路由管理

模拟路由跳转的封装官方跳转文档

const navigateTo = (params) => {
	let token = uni.getStorageSync("token");
	//别的操作
	if(token){
		//可以再做一次token校检
		uni.navigateTo(params)
	}else{
		uni.redirectTo("login=?"+params.url)
	}
}

const redirectTo = (params) => {
	let token = uni.getStorageSync("token");
	//别的操作
	if(token){
		//可以再做一次token校检
		uni.redirectTo(params)
	}else{
		uni.redirectTo("login=?"+params.url)
	}
}

const reLaunch = (params) => {
	let token = uni.getStorageSync("token");
	//别的操作
	if(token){
		//可以再做一次token校检
		uni.reLaunch(params)
	}else{
		uni.redirectTo("login=?"+params.url)
	}
}


const switchTab = (params) => {
	let token = uni.getStorageSync("token");
	//别的操作
	if(token){
		//可以再做一次token校检
		uni.switchTab(params)
	}else{
		uni.redirectTo("login=?"+params.url)
	}
}

const navigateBack = (params) => {
	let token = uni.getStorageSync("token");
	//别的操作
	if(token){
		//可以再做一次token校检
		uni.navigateBack(params)
	}else{
		uni.redirectTo("login=?"+params.url)
	}
}


const preloadPage = (params) => {
	let token = uni.getStorageSync("token");
	//别的操作
	if(token){
		//可以再做一次token校检
		uni.preloadPage(params)
	}else{
		uni.redirectTo("login=?"+params.url)
	}
}

module.exports = {
	navigateTo,
	redirectTo,
	reLaunch,
	switchTab,
	preloadPage
}

当然以上的封装为了可以方便使用,可以在main.js里面挂载到vue实例上或者直接使用mixin混入到app.vue组件中

uni-simple-router

一个更为简洁的Vue-router,专为 uni-app 量身打造

介绍

uni-simple-router 是专为 uni-app 打造的路由器。它与 uni-app 核心深度集成,使使用 uni-app 轻松构建单页应用程序变得轻而易举。功能包括:

  • H5端 能完全使用 vue-router 进行开发。
  • 模块化,基于组件的路由器配置。
  • 路由参数,查询,通配符。
  • H5端 查看由 uni-simple-router 过渡系统提供动力的过渡效果。
  • 更细粒度的导航控制。
  • H端自动控制活动的CSS类链接。
  • 通配小程序端、APP端、H5端。
安装uni-simple-router
  1. 插件市场直接使用HBuilder导入

因为uni-simple-router官方文档推荐使用npm安装,HBuilder导入需要自己捣鼓;所以我在网上找了类似的案例, 找到一个可行方案如下!压缩包链接:uni-simple-router

目录如下

image.png

  • 将压缩包解压到指定的目录下,我是创建了一个js_sdk的目录
  • 创建router目录,这里面的路由声明以及路由拦截跟Vue-router用法是一模一样的;
  • router/index.js
import modules from './modules'
import Vue from 'vue'
import Router from '@/js_sdk/uni-simple-router/index.js'
Vue.use(Router)
//初始化
const router = new Router({
	encodeURI:true,  
    routes: [...modules]//路由表
});
const whiteList = ['/pages/login/login'] 
//全局路由前置守卫
router.beforeEach((to, from, next) => {
	let token='token';
	if(token){
		 next()
	}else{
		if (whiteList.indexOf(to.path) !== -1) {
		  next()
		}else{
		  next({ path: '/pages/login/login'})
		}
	} 
})
// 全局路由后置守卫
router.afterEach((to, from) => {
	console.log("afterEach")
})
export default router;

main.js

import Vue from 'vue'
import App from './App'
import router from './common/router'
import {RouterMount} from './js_sdk/uni-simple-router/index.js'

Vue.config.productionTip = false

App.mpType = 'app'

const app = new Vue({
    ...App
})
// #ifdef H5
	RouterMount(app,'#app');
// #endif

// #ifndef H5
	app.$mount(); //为了兼容小程序及app端必须这样写才有效果
// #endif

  1. npm安装,router使用方式跟vue是一样的
npm install uni-simple-router --save

注意

router里面的页面路径一定要跟pages.json中pages的保持一致

常用API
  1. Router 实例方法
router.beforeEach((to, from, next) => {
  // `to` 和 `from` 都是路由对象
})

router.afterEach((to, from) => {
  // `to` 和 `from` 都是路由对象
})
router.push({name:'tab1'})
router.replace({name:'tab1'})
router.replaceAll({name:'tab1'})
router.pushTab({name:'tab1'})
router.back(2,{
    success:(...arg)=>{
        console.log(arg)
    }
})
  1. uni-app官方路由跳转方法'链接'
// 保留当前页面,跳转到应用内的某个页面,使用uni.navigateBack可以返回到原页面。
// 2.8.9+ 支持
uni.navigateTo({
  url: 'pages/test?id=1',
  events: {
    // 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据
    acceptDataFromOpenedPage: function(data) {
      console.log(data)
    },
    someEvent: function(data) {
      console.log(data)
    }
    ...
  },
  success: function(res) {
    // 通过eventChannel向被打开页面传送数据
    res.eventChannel.emit('acceptDataFromOpenerPage', { data: 'test' })
  }
})

// 关闭当前页面,跳转到应用内的某个页面。
uni.redirectTo({
    url: 'test?id=1'
});

// 关闭所有页面,打开到应用内的某个页面
uni.reLaunch({
    url: 'test?id=1'
});

// 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
uni.switchTab({
    url: '/pages/index/index'
});

// 关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages() 获取当前的页面栈,决定需要返回几层。
// 注意:调用 navigateTo 跳转时,调用该方法的页面会被加入堆栈,而 redirectTo 方法则不会。见下方示例代码

// 此处是A页面
uni.navigateTo({
    url: 'B?id=1'
});

// 此处是B页面
uni.navigateTo({
    url: 'C?id=1'
});

// 在C页面内 navigateBack,将返回A页面
uni.navigateBack({
    delta: 2
});

// 预加载页面,是一种性能优化技术。被预载的页面,在打开时速度更快。
uni.preloadPage({url: "/pages/test/test"});

request工具封装

在vue的项目中我们用的最多的是axios来作为前端http请求的工具,那么其实在uni-app中也是提供了这类api直接使用. 但是在实际项目中,我们为了代码易于维护并且减少我们的代码量,都会再做一次封装。那么下面我们看下对于request的封装 我们需要做哪些事情

  1. 因为没有axios的请求拦截api,所以我们需要在真正请求之前做一些全局的判断以及设置包括: 请求URL,自定义请求头,请求超时,是否登录,根据请求方式设置content-type,以及参数转义
  2. 请求成功之后的成功 失败 以及无响应缺省操作
  3. 返回给api请求的相应数据结构重组
import operate from '../common/operate.js' // 接口地址的域名
// vuex 的使用  详情参考官网 https://uniapp.dcloud.io/vue-vuex
import store from '../store/index.js'  

export default class Request {
    http(param) {
		let token = store.getToken() || ""
		if (!token) {
			// 这里处理没有token认证逻辑
		}
        // 请求参数
        var url = param.url,
            method = param.method,
            header = {},
            data = param.data || {},
            hideLoading = param.hideLoading || false;

        //拼接完整请求地址
        var requestUrl = operate.api + url;

        //请求方式:GET或POST(POST需配置
        // header: {'content-type' : "application/x-www-form-urlencoded"},)
        if (method) {
            method = method.toUpperCase(); //小写改为大写
            if (method == "POST") {
                header = {
                    'content-type': "application/x-www-form-urlencoded"
                };
            } else {
                header = {
                    'content-type': "application/json"
                };
            }
        }

        //加载圈
        if (!hideLoading) {
            uni.showLoading({
                title: '加载中...'
            });
        }

        // 返回promise
        return new Promise((resolve, reject) => {
            // 请求
            uni.request({
                url: requestUrl,
                data: data,
                method: method,
                header: header,
                success: (res) => {
                    // 判断 请求api 格式是否正确
                    if (res.statusCode && res.statusCode != 200) {
                        uni.showToast({
                            title: "api错误" + res.errMsg,
                            icon: 'none'
                        });
                        return;
                    }
                    // code判断:200成功,不等于200错误
                    if (res.data.code) {
                        if (res.data.code != '200') {
                            uni.showToast({
                                title: "" + res.data.msg,
                                icon: 'none'
                            });
                            return;
                        }
                    } else {
                        uni.showToast({
                            title: "code!=200" + res.data.msg,
                            icon: 'none'
                        });
                        return;
                    }
                    // 将结果抛出
                    resolve(res.data)
                },
                //请求失败
                fail: (e) => {
                    uni.showToast({
                        title: "" + e.data.msg,
                        icon: 'none'
                    });
                    resolve(e.data);
                },
                //请求完成
                complete() {
                    //隐藏加载
                    if (!hideLoading) {
                        uni.hideLoading();
                    }
                    resolve();
                    return;
                }
            })
        })
    }
}

UI组件如何引入

在实际业务项目中经常会使用到第三方的插件,如果是用vue-cli安装的项目直接用npm安装然后引入使用就可以。 但是如果是使用HBuilder创建的项目需要参考easycom的组件规范引入组件然后才能使用 easycom组件规范

传统vue组件,需要安装、引用、注册,三个步骤后才能使用组件。easycom将其精简为一步。 只要组件安装在项目的components目录下或uni_modules目录下,并符合components/组件名称/组件名称.vue目录结构。 就可以不用引用、注册,直接在页面中使用。

不管components目录下安装了多少组件,easycom打包后会自动剔除没有使用的组件,对组件库的使用尤为友好。

不满足easycom规范的组件如何使用

  1. 第一种方法:如果你的组件名称或路径不符合easycom的默认规范, 可以在pages.json的easycom节点进行个性化设置,自定义匹配组件的策略
"easycom": {
  "autoscan": true, // 开启扫描
  "custom": {
    "^uni-(.*)": "@/components/uni-$1.vue", // 匹配components目录内的vue文件
    "^vue-file-(.*)": "packageName/path/to/vue-file-$1.vue" // 匹配node_modules内的vue文件
  }
}
  1. 第二种方法: 直接采用vue的组件引用的方法也可以满足,组件安装 引用 注册 注意

easycom组件规范只能满足vue文件的组件,其他文件格式的组件无法满足

如何把uni-app项目运行到微信开发者工具

1,先在HBuilder X中找到项目的manifeast.json文件 

2,点击du小程序对应的

3,将自己的小程序的appid配置进去即可 image.png 1,在HBuilder X中找到导航栏中的工具

2,点击工具,然后点击运行配置

3,找到小程序运行配置,填写自己的小程序所在路径(不知道可以右键点击打开文件所在位置)

image.png 1,查看HBuilder X中项目内的的manifest

2,找到基础配置,查看其中的uni-app的appid是不是没填,没有填写的话点击后面的获取,自动获取填上即可

image.png 找到微信开发者工具的设置---->通用设置---->安全,然后将服务端口打开即可正常使用了

如果还是没有成功的话,可以看看是不是因为只是快捷方式里的设置了,可以到开发者工具的所在文件夹下打开开发者工具,登录后再进行设置。个人遇到了这种问题,刚开始通过快捷方式打开服务端口设置了但是一直无法运行,后来没有通过快捷方式而是在文件夹内打开了开发者工具,发现里面的服务端口居然是关闭的!然后打开后就正常了。

项目结构 image.png 页面结构 遵循 VUE 单页面结构 只能有一个 template,一个script,可以有多个style

<template>

       // 布局
</template>
<script>
       export default {
 // data 必须声明为返回一个初始数据对象的函数;否则页面关闭时,数据不会自动销毁,再次打开该页面时,会显示上次数据
 
  data() {

         return {

                    title: 'Hello'

                     }
              },

              onLoad(e){

                     // 页面生命周期方法

              },

              methods: {

                     // 自定义方法,例如点击事件等

              }

       }

</script>

 

<style>

       // 设置样式

</style>

页面路由

uni-app路由全部交给框架统一管理,开发者需要在pages.json里配置每个路由页面的路径及页面样式


{

    "pages": [

        {

            "path": "pages/index/index", // index 页面

            "style": {

                            // 具体配置参考 https://uniapp.dcloud.io/collocation/pages?id=style

                     }

        }, {

            "path": "pages/login/login", // login 页面

            "style": {         
                     }
        }

    ]

}

尺寸单位

uni-app支持的通用css单位包括px、upx、vh。 px 即屏幕像素 upx 是uni-app提供的一种根据屏幕宽度自适应的动态单位。以750宽的屏幕为基准,屏幕变宽,upx实际显示效果会等比放大。 vh 是视窗高度的百分比 举例说明: 若设计稿宽度为 750px,元素 A 在设计稿上的宽度为 100px,那么元素 A 在 uni-app 里面的宽度应该设为:750 * 100 / 750,结果为:100upx。 若设计稿宽度为 640px,元素 A 在设计稿上的宽度为 100px,那么元素 A 在 uni-app 里面的宽度应该设为:750 * 100 / 640,结果为:117upx。

若设计稿宽度为 375px,元素 B 在设计稿上的宽度为 200px,那么元素 B 在 uni-app 里面的宽度应该设为:750 * 200 / 375,结果为:400upx。

小程序开发注意

#各家小程序实现机制不同,可能存在的平台兼容问题

  1. 浏览器内核差异 各家小程序的浏览器内核不同,可能会造成css兼容性问题,更多细节参考:ask.dcloud.net.cn/article/131…
  2. 自定义组件渲染差异 微信(可以使用virtualHost配置)/QQ/百度/字节跳动这四家小程序,自定义组件在渲染时会比App/H5端多一级节点,在写样式时需要注意:
  • 使用flex布局时,直接给自定义组件的父元素设置为display:flex不能影响到自定义组件内部的根节点,需要设置当前自定义组件为display:flex才可以。
  • 在自定义组件内部设置根元素高度为100%,不能撑满自定义组件父元素。需要同时设置当前自定义组件高度为100%才可以。 支付宝小程序不会插入节点,不存在如上问题。

#vendor.js 过大的处理方式

小程序工具提示vendor.js过大,已经跳过es6向es5转换。这个转换问题本身不用理会,因为vendor.js已经是es5的了。 关于体积控制,参考如下:

  • 使用运行时代码压缩
    • HBuilderX创建的项目勾选运行``-->``运行到小程序模拟器``-->``运行时是否压缩代码
    • cli创建的项目可以在package.json中添加参数--minimize,示例:"dev:mp-weixin": "cross-env NODE_ENV=development UNI_PLATFORM=mp-weixin vue-cli-service uni-build --watch --minimize"