uni-app 是一个 使用 Vue.js 开发全部前端应用的框架,是一种终极的跨平台解决方案,这里的平台,主要指的是 App平台(android、ios)、 小程序平台、 H5平台。开发者编写一套代码,可发布到iOS、Android、H五、以及各类小程序(微信/支付宝/百度/头条/QQ/钉钉)等多个平台。
uni-app将经常使用的组件和api进行了跨平台封装,而且 保持与微信小程序的组件和api一致,同时兼容以微信的方式去调用api,即 在uni-app中除了可使用全局的uni对象去调用微信小程序中同名的api还可使用全局的wx对象去调用api。uni-app使用 vue的语法以及 微信小程序api,因此学习成本很是低。
<script> export default { onLoad() { uni.showLoading({ title: '加载中-uni' }); // 两者是等价的 wx.showLoading({ title: '加载中-uni' }) } } </script>
① pages.json : 该文件是用来对 uni-app 进行全局配置,决定页面文件的路径(pages)、窗口样式(globalStyle)、原生的导航栏(globalStyle)、底部的原生tabbar(tabBar) 等。
它相似微信小程序中app.json的页面管理部分。须要注意的是,微信小程序权限配置也是在app.json文件中,经过permission进行配置,而uni-app则将权限配置移到了manifest.json文件中。css
② manifest.json: 该文件是应用的配置文件,主要用于指定应用的名称、图标、权限等。html
③ App.vue : 该文件是应用的主组件,全部页面都是在App.vue下进行切换的,是页面入口文件,在这个文件里,你能够初始化一些通用的组件,调用一些应用生命周期函数,应用生命周期(onLaunch、onShow、onHide)仅可在App.vue中监听,在其它页面监听无效,以及设置一些全局的样式,即在App.vue中的<style></style>内置设置全局样式。前端
④ main.js: 该文件是应用的入口文件,主要做用是初始化App.vue主组件并安装须要的插件,如vuex,须要注意的是,uni-app中是不能使用vue-router插件的,由于路由须在pages.json中进行配置。vue
// main.jsandroid
import Vue from 'vue' import App from './App' Vue.config.productionTip = false App.mpType = 'app' const app = new Vue({ // ①官方写法 ...App }) // const app = new Vue(App); // ②等价于上面的写法 // const app = new Vue({ // ③可正常渲染出页面,但onLaunch、onShow、onHide应用生命周期失效 // render: h => h(App) // }); app.$mount()
main.js中官方写法是在建立Vue实例的时候传入一个对象,而且对根组件App.vue进行解构后传入, 其写法和直接传入根组件是同样的,可是若是经过写法③虽然能够正常渲染出页面,可是 根组件上的应用生命周期函数将失效
⑤ pages文件夹: 主要用于存放应用中的页面,应用中的页面就是.vue组件。ios
⑥ static文件夹: 主要用于存放应用中的图片等静态资源。vue-router
⑦ uni.scss: 主要存放uni-app内置的经常使用样式变量。vuex
⑧ unpackage文件夹: 主要存放uni-app编译运行后生成的打包相关输出文件。json
① 初始化项目小程序
打开HBuilderX IDE,新建一个名称为 mini-video的初始化uni-app项目,这里 勾选uni-app便可建立,项目建立完成后,打开pages/index/index.vue, 将<template>中的模板内容content部分清空,将uni-app初始项目中与应用无关的东西进行清空、修改便可。
② 建立底部导航栏组件
首先要弄清楚咱们的uni-app已经提供了tabBar的配置,即提供了底部导航栏的,那为何还须要自定义底部导航栏呢 ?由于uni-app提供的默认底部导航栏tabBar的背景颜色 只支持十六进制,因此 没法设置为透明。同时咱们又须要将底部导航栏中的页面设置为tabBar页面,因此咱们 仍是要进行tarBar的配置,而一配置tabBar,那么就会自动出现uni-app提供的默认导航栏,因此咱们 必须在应用启动onLaunch的时候将默认tabBar进行隐藏,那么没有了默认导航栏,咱们怎么进行tabBar页面的切换呢?咱们能够经过 <navigator>组件设置不一样的跳转方式,实现应用内各类页面之间的跳转。记住 APP和微信小程序是不支持<a>标签跳转的。
底部导航栏有五个页面: 首页(index.vue)、关注(follow.vue)、加号(添加好友friend.vue)、消息(news.vue)、我(personal.vue)。因此须要在pages中模仿index新建出剩余的四个页面,页面新建完成后,须要配置到pages.json中的tarBar中,只须要配置list便可,如:
{ "tabBar": { // 在pages.json中添加上tabBar配置,以下 "list": [ {"pagePath":"pages/index/index"}, {"pagePath":"pages/follow/follow"}, {"pagePath":"pages/friend/friend"}, {"pagePath":"pages/news/news"}, {"pagePath":"pages/personal/personal"} ] } }
// App.vue中onLaunch的时候隐藏掉uni-app自带的tabBar
<script> export default { setTimeout(() => { uni.hideTabBar(); // 隐藏tabBar }, 1000); } </script>
在ios和安卓App平台上运行时,会出现tabBar隐藏失败的状况,解决办法就是 隐藏的时候须要添加一个1000ms左右的延迟
// 项目根目录下新建一个components目录,并在其中新建一个tab-bar.vue即自定义底部导航栏组件
<template> <view class="tab"> <navigator open-type="switchTab" url="/pages/index/index" class="tab-box"> 首页 </navigator> <navigator open-type="switchTab" url="/pages/follow/follow" class="tab-box"> 关注 </navigator> <view class="tab-box"> + <!--暂时用加号代替,后面会替换成字体图标--> </view> <navigator open-type="switchTab" url="/pages/news/news" class="tab-box"> 消息 </navigator> <navigator open-type="switchTab" url="/pages/personal/personal" class="tab-box"> 我 </navigator> </view> </template> <style> .tab{ height:50px; width:100%; position:fixed; bottom: 0; left: 0; z-index: 20; } .tab-box{ float: left; width: 20%; color: #FFFFFF; text-align: center; height: 50px; line-height: 50px; font-size:20px } .icon-box{ width: 60%; height: 30px; background: #FFFFFF; color: #000000; margin: 10px 20%; line-height:30px; border-radius: 5px; font-size: 15px; } </style>
③ 添加图标字体
添加图标字体很是简单,就是登陆 iconfont网站,而后 建立一个图标项目,而后搜索本身须要的图标,好比 加号、 搜索、 返回,将它们加入到项目中,而后点击下载便可,下载完成后解压,找到 iconfont.css这个文件,这个就是咱们要用到的图标字体的css样式,直接引入到项目中便可,为了方便使用, 咱们将图标字体css文件做为一个全局样式引入到App.vue组件中。使用的时候,咱们只须要在须要添加图标字体的标签上, 添加上"iconfont 具体的图标样式名"便可,如:
// App.vue
<style> /*每一个页面公共css */ @import url("./static/iconfont.css"); </style>
// components/tab-bar.vue
<view class="tab-box"> <view class="iconfont icon-jiahao icon-box" ><!--添加一个加号图标字体样式,注意是两个样式名哦--> </view> </view>
④ 建立首页头部导航栏
首页头部导航栏,最左侧是一个搜索图标,中间是推荐和同城,右侧无内容。一样,咱们的uni-app是有一个默认头部导航栏的,因此咱们首先要隐藏掉默认的头部导航栏,要隐藏默认头部导航栏,咱们 须要在pages.json文件中设置其navigationStyle属性值为custom即自定义,如:
{ "globalStyle": { "navigationStyle":"custom" // 设置头部导航栏为自定义模式,头部导航栏会自动消失 } }
// /components/index-header.vue
<template> <view class="index-header"><!--固定定位到首页顶部--> <view class="iconfont icon-icon-- icon"></view> <!--绝对定位到左侧--> <view class="middle"> <!--搜索图标绝对定位后,middle将会上移动到顶部,在搜索图标下面,里面内容居中显示便可--> <view class="text">推荐</view>| <view class="text">同城</view><!--变成行内元素--> </view> </view> </template> <style scoped> .index-header { height: 35px; line-height: 35px; width: 100%; position: fixed; top: 25px; left: 0; margin: 0 auto; background: #000000; z-index: 20; } .icon { position: absolute; left: 0; top: 0; color: white; width: 20%; text-align: center; } .middle { text-align: center; color: white; } .text { display: inline; margin: 0 10px; } </style>
⑤ 建立视频播放组件
视频播放组件即一个 全屏的页面,而后里面嵌入一个<video>组件便可实现。这里须要特别说一下如何让页面全屏显示,咱们设置页面全屏一般会让须要全屏的元素设置上 width: 100%; height: 100%;但是当咱们给视频播放组件根元素标签设置上width为100%,height为100%后,它并无全屏显示,由于当 样式属性值为百分数的时候, 其是相对于父元素的,便是父元素宽高的100%,而此时视频播放组件的父元素是 html、 body, 它们并无设置宽高,因此 咱们须要在App.vue中设置一下全局样式,将html和body的宽高设置为100%,此后其中的子元素设置百分数的时候才会其做用。
// App.vue
html,body { width: 100%; height: 100%; margin: 0; padding: 0; }
// /components/video-player.vue
<template> <view class="video-player"> <video class="video" :src= "video.src" :controls="false" :loop="true"> </video> </view> </template> <script> export default { props: ["video"] } </script> <style> .video-player { width: 100%; height: 100%; } .video { width: 100%; height: 100%; z-index: 19; } </style>
⑥ 建立视频列表组件
视频列表组件,咱们使用的是<swiper>组件,里面<swiper-item>部分则为上面的视频播放组件。
// /components/video-list.vue
<template> <view class="video-list"> <view class="swiper-box"> <swiper class="swiper" :vertical="true"> <swiper-item v-for="(item,index) in videos" :key="index"> <view class="swiper-item"> <video-player :video="item" :index="index"> </video-player> </view> </swiper-item> </swiper> </view> </view> </template> <script> import VideoPlayer from "./video-player.vue"; export default { components: { "video-player": VideoPlayer }, props:['list'], data() { return { videos:[], } }, watch:{ list(){ this.videos=this.list; } } } </script> <style scoped> .video-list { width: 100%; height: 100%; } .swiper-box{ height:100%; width: 100%; } .swiper{ height:100%; width: 100%; } .swiper-item { width: 100%; height: 100%; background: red; } </style>
⑦ 向视频列表组件传入列表数据
视频列表组件和视频播放组件都已经完成后,就能够在 首页onLoad的时候获取视频数据,而后传递给视频列表组件,视频列表组件在遍历传递过来的视频列表将视频地址传入对应的视频播放组件中便可,这里采用mock数据的方式提供视频列表。
// pages/index/index.vue
<template> <view class="content"> <index-header></index-header> <!--首页头部导航栏组件--> <video-list :list="list"></video-list> <!--视频列表组件--> <tab-bar></tab-bar> <!--首页底部导航栏组件--> </view> </template> <script> import TabBar from "../../components/tab-bar.vue"; import IndexHeader from "../../components/index-header.vue"; import VideoList from "../../components/video-list.vue"; export default { components: { "tab-bar": TabBar, "index-header": IndexHeader, "video-list": VideoList }, data() { return { list: [] } }, onLoad() { this.getVideos(); }, methods: { getVideos() { const res = [ { id: 0, src: "http://alimov2.a.yximgs.com/bs2/gdtPostRoll/postRoll-MTA3MDY0NDY3Mzk.mp4", autho: "张三", title: "仙娜美", loveNumber: 10000, commentNumber: 2000, shareNumber: 30000 }, { id: 1, src: "http://upmov.a.yximgs.com/upic/2019/02/13/22/BMjAxOTAyMTMyMjUxMTlfNDc4ODM2MzlfMTA3Mjc5ODU2MjhfMV8z_b_B1fbc185eaca8cc06efa2d4f713e13e8c.mp4", autho: "李四", title: "【搞笑】最强猜歌王", loveNumber: 40000, commentNumber: 5000, shareNumber: 60000 }, { id: 2, src: "http://bdmov.a.yximgs.com/bs2/gdtPostRoll/postRoll-MTA3MDk5Mjc5OTg.mp4", autho: "王五", title: "特制流泪芥末酱", loveNumber: 70000, commentNumber: 8000, shareNumber: 90000 } ]; this.list = res; } } } </script> <style> .content { width: 100%; height: 100%; } </style>