uni-app開發一個小視頻應用(一)

1、uni-app簡介

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>

uni-app框架圖

2、uni-app初始目錄及文件介紹

① 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

3、開始開發一個小視頻應用

① 初始化項目小程序

打開HBuilderX IDE,新建一個名稱爲 mini-video的初始化uni-app項目,這裏 勾選uni-app便可建立,項目建立完成後,打開pages/index/index.vue, 將<template>中的模板內容content部分清空,將uni-app初始項目中與應用無關的東西進行清空、修改便可。

mini-video

② 建立底部導航欄組件

首先要弄清楚咱們的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%,而此時視頻播放組件的父元素是 htmlbody它們並無設置寬高,因此 咱們須要在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>
相關文章
相關標籤/搜索