項目源代碼地址:https://github.com/Mstian/wanAndroid (求個star)
項目簡書博客地址:http://www.lxweimin.com/p/1557569e1b15
項目掘金博客地址https://juejin.im/post/5deb1d1a6fb9a016023e7633
項目下載地址:https://www.pgyer.com/pv0D 邀請碼4566
掃一掃下載體驗
1. 項目截圖
首頁
首頁
登錄
登錄
注冊
注冊
個人中心
個人中心
體系
體系
公眾號
公眾號
項目
項目
導航
導航
搜索
搜索
我的收藏
我的收藏
2. 項目結構
項目結構腦圖
unpackage
unpackage文件夾主要存放打包后的文件,
官方說有的圖片,文件可以放到這里,
不過我都放在了static文件夾中
App.vue
里面的可以監控App的生命周期,
可以隨時監控Appshow Apphide,
并做出相應反應操作。
main.js
入口文件,主要引入公共使用工具,
并掛載到Vue原型上,以作全局方便使用。
manifest.json
打包配置使用,例如我在項目中使用了
高德地圖就需要配置高德地圖appkey。
還有打包時的app圖標,啟動頁圖片等等。
pages.json
頁面配置,tabbar配置,調試配置
common
common文件夾主要存放
公用css以及公用js文件 還有
項目中使用到的iconfont以及
自己封裝的ajax請求等
components
components主要用來存放
公用的組件例如彈窗,加載更多,
回到頂部,等等。
pages
pages文件夾主要存放
正常開發的頁面,例如首頁,
個人中心,登錄頁等等
static
static文件夾我用來存放
本地使用到的一些圖片。
例如tabbar的icon等。
store
store文件夾,vuex數據狀態集中管理工具,
vuex中我主要存了用戶的一些信息,比如用戶名
在各個組件中需要使用時可以公用
README.md
主要存放一些平時開發中的記錄
比如有一些問題當時不能解決的,可以記錄下來
或者某處使用的技術不成熟的等等,我當記事本用了
uni-app 使用vue的語法+小程序的標簽和API
頁面文件遵循 Vue 單文件組件 (SFC) 規范
組件標簽靠近小程序規范,詳見uni-app 組件規范
接口能力(JS API)靠近微信小程序規范,但需將前綴wx
替換為uni
,詳見[uni-app接口規范]
數據綁定及事件處理同Vue.js
規范,同時補充了App及頁面的生命周期
為兼容多端運行,建議使用flex布局進行開發
項目的結構類似于Vue單頁面應用結構,也類似于微信小程序項目結構配置,具體的請查看uniapp官網
3. 項目功能
- 首頁banner,文章列表
- 體系列表
- 搜索文章
- 公眾號列表
- 項目列表
- 導航分類
- 個人中心
- 注冊登錄
- 收藏
- 常用網站
- 本機信息
4. 項目技術分析
實際上項目中也沒有使用到特別復雜的技術,很多東西也都是對照著官方文檔去寫的,遇到不會的或者自己查不出來的就去社區提提問題,Dcloud社區環境還不錯,遇到很多問題可以去社區提問,官方回答也還挺活躍,并且也可以去回答別人問題,總的來說很不錯吧。
點擊進入社區地址
4.1 頂部導航欄
頂部導航欄根據需求分為兩種,一種為原生導航欄,一種為禁止原生導航欄從而自定義導航欄
兩種導航欄各有好處,官網如是說:
uni-app 自帶原生導航欄,在pages.json里配置。
原生導航的體驗更好,渲染新頁面時,原生導航欄的渲染無需等待新頁面dom加載,可以在新頁面進入動畫開始時就渲染。
原生導航還可以避免滾動條通頂,并方便的控制原生下拉刷新。
通過pages.json的配置,可以簡單的、跨端的、高性能的開發業務。
但原生導航欄的擴展能力有限的。尤其是微信下,沒有提供太多導航欄的配置。
在App下,pages.json里每個頁面的app-plus下可以設置titleNView等更多參數,可以得到比微信小程序更豐富的擴展性。
另外,開發者也可以在必要時取消原生導航欄,使用view自行繪制導航欄。
我在首頁中禁止了原生導航欄,使用了可自由發揮制作的自定義導航欄
頂部欄分為狀態欄和內容區域,狀態欄即為顯示時間運營商等狀態的最上面一欄,安卓手機狀態欄高度不統一,uniapp提供css變量(--status-bar-height)自動獲取不同機型狀態欄高度,為了風格統一下面content區域一般都固定為44px,如有特殊需求,可以適當增加高度。
左邊頭像區域可點擊,進入個人主頁,右邊搜索按鈕可點擊進入搜索頁面
部分代碼如下:
{
"path": "pages/home/home",
"style": {
"navigationStyle": "custom", //pages.json中禁用原生導航欄
"enablePullDownRefresh": true,
"app-plus": {
"pullToRefresh": {
"support": true,
"color": "#DD524D",
"offset": "70px"
}
}
}
}
//自定義導航欄
<view class="header">
<view class="status_bar"></view>
<view class="header_content">玩安卓</view>
<view class="pendant">
<view @click="toMine()" class="avatar bgimg" :style="{ backgroundImage: 'url(' + bgImg + ')' }"></view>
<view @click="toSearch()" class="search iconfont icon-sousuo"></view>
</view>
</view>
<style>
.status_bar{
height: var(--status-bar-height);
width: 100%;
}
.header_content{
width: 100%;
height: 44px;
line-height: 44px;
text-align: center;
color: #fff;
}
</style>
4.2 列表渲染
因為這個開源項目由于大多數都是文章列表所以列表的渲染部門比較多,我在項目中才用了兩種方式,一種就是普通的vue頁面列表渲染,另外一種就是使用nvue組件<list>去渲染;第一種沒什么好說的,直接使用v-for遍歷數據進行渲染,可以觸發pages.json配置的下拉刷新、頁面觸底onReachBottomDistance、titleNView的transparent透明漸變等。
部分代碼如下:
onPullDownRefresh() { //下拉刷新 監聽到下拉操作時進行邏輯操作
this.reload = true;
this.pageSize = 0;
this.getArticleData(this.pageSize);
},
onReachBottom() { //上拉加載 監聽到上拉操作時進行邏輯操作
this.reload = false;
this.pageSize++;
this.getArticleData(this.pageSize);
}
同時還有一個列表滑動到一定位置,出現回到頂部按鈕,點擊回到頂部按鈕回到頂部。
onPageScroll(scrollTop){ //控制回到頂部按鈕顯示與隱藏
if(scrollTop.scrollTop >= 200){
this.isTop = true
}else{
this.isTop = false
}
},
toTop(){ //點擊按鈕調用api回到頂部
uni.pageScrollTo({
scrollTop: 0,
duration: 300
});
}
使用場景首頁
第二種則不同,第二種是由于我要做tab選項卡的功能,最后決定采用nvue <list> 組件,并且同時使用了<refresh> <loading>組件添加下拉刷新,上拉加載功能。
nvue是什么?怎么用?
頂部選項卡部分處理的不是特別好,使用了scroll-view和swiper結合去做,第一次加載一組數據,每切換一次選項卡,再重新加載一次數據,相當于就是說,每一組數據渲染了當前所有的swiper所以體驗不好,很難受,看官方說每次緩存當前選項卡附近三條,具體的沒有研究,項目里的選項卡處理是一個后續待優化的問題。
部分代碼如下:
//tab部分
<scroll-view class="scroll_top" show-scrollbar="false" scroll-with-animation="true" scroll-x="true" :scroll-into-view="scrollIntoView">
<view v-for="(item,index) in tabsList" :key="index" class="tabs" :id="'tabId'+index">
<text @click="changeTabs(index)" class="tabtxt" :class="tabIndex == index ? 'active' : ''">{{item.name}}</text>
</view>
</scroll-view>
//內容部分
<swiper class="swiper" :current="tabIndex" :indicator-dots="false" :autoplay="false" :interval="3000" :duration="1000" @change="swiperChange">
<swiper-item class="swiper_item" v-for="(item,index) in tabsList" :key="index">
<list class="list" loadmoreoffset="15" @loadmore="loadMore(index)">
<refresh class="refresh" @refresh="onrefresh(index)" @pullingdown="onpullingdown" :display="refreshing ? 'show' : 'hide'">
<loading-indicator class="loading-icon" animating="true" v-if="refreshing"></loading-indicator>
<text class="loading_txt">{{refreshTxt}}</text>
</refresh>
<cell class="cell" v-for="(dataitem,dataindex) in contentList" :key="dataindex">
<listItem :dataItem="dataitem" :dataindex="dataindex"></listItem>
</cell>
<cell class="loading-more" v-if="isLoading">
<text class="loading-more-text">{{loadingText}}</text>
</cell>
</list>
</swiper-item>
</swiper>
實際上uniapp提供了豐富的插件,插件市場有很多官方人員與開發者共同開發的優質插件,如果有一些特殊需求也可以在插件市場提出,如果有人感興趣,可以幫你開發哦。
點擊去插件市場
4.3 數據請求
數據請求使用uniapp自身的api,uni.request(OBJECT),在此基礎上做了簡單的封裝,有利于統一部分的實現,比如showLoading,hideLoading,還有利于自己調試。
請求部分代碼如下:
const ajaxJs = function(url,data,method,success,fail,complete){
uni.showLoading({
title: '加載中',
});
uni.request({
url:url,
data:data,
header: {
'content-Type': 'application/json'
},
method:method,
responseType:'text',
dataType: 'json',
responseType: 'text',
success:function({data}){
// console.log(data);
if(data.errorCode == 0){
uni.hideLoading()
if( success && typeof (success) == "function"){
success(data)
console.log(data,'請求成功'+"--"+url);
}
}else{
uni.hideLoading()
// console.log(data,'error');
}
},
fail:function(data){
uni.hideLoading()
if( fail && typeof (fail) == "function"){
fail(data)
}
console.log(data,'請求出錯'+"--"+url);
},
complete:function(data){
uni.hideLoading()
if( complete && typeof (complete) == "function"){
complete(data)
}
console.log(data,'complete'+"--"+url);
}
})
}
export default{
ajaxJs
}
為了統一管理請求地址,在common文件夾中建立requesturl文件夾用來存放所有接口:
const baseUrl = "https://www.wanandroid.com";
export default{
// 首頁
_url_home_banner : baseUrl + "/banner/json",
_url_home_article : function(pageSize){
return baseUrl + "/article/list/" + pageSize + "/json"
},
_url_register : baseUrl + "/user/register",
_url_login : baseUrl + "/user/login",
_url_system : baseUrl + "/tree/json",
_url_nav : baseUrl + "/navi/json",
_url_website:baseUrl + "/friend/json",
_url_hotkey: baseUrl + "/hotkey/json",
_url_search: function(pageSize,k){
return baseUrl + "/article/query/"+ pageSize +"/json?k="+k
},
_url_logout:baseUrl + "/user/logout/json",
_url_collect_list: function (pageSize){
return baseUrl + "/lg/collect/list/"+ pageSize +"/json"
}
}
全部暴露出去,在main.js中掛載到Vue原型上,方便調用。
注意:在nvue中無法訪問到Vue原型上屬性,因此在nvue中我是單獨寫的接口。
4.4 其他技術應用
webview:在加載文章詳情頁的時候使用了webview組件;
web-view 是一個 web 瀏覽器組件,可以用來承載網頁的容器,會自動鋪滿整個頁面。
<web-view :webview-styles="webviewStyles" :src="url"></web-view>
其中可以配置webviewStyles,加載進度等,具體可查看官方文檔。
高德地圖:調用uniapp的api獲取當前地址,然后通過本機地圖打開,這里我使用的是高德地圖,使用高德地圖需要去成為開發者,獲取appkey,打包時在manifest.json文件中進行配置。
點擊去高德地圖開發平臺
事件通訊:使用uniapp通訊api,uni.on()監聽事件,使用場景,例如登錄之后,首頁渲染的數據列表都是未登錄的狀態,(因為登錄后收藏過的文章收藏按鈕需要變色),所以登錄完成之后需要通知首頁去刷新,重新攜帶用戶數據去拉取數據,所以采用這個通訊機制。包括退出也是。
//登錄后通知其他頁面已登錄
uni.$emit("login")
uni.$on("login", function() { //監聽登錄賬號
uni.startPullDownRefresh();
});
uni.$on("logout", function() { //監聽退出賬號
uni.startPullDownRefresh();
});
本地存儲:歷史搜索數據,存到了本地內存中,當當前用戶退出登錄時清理掉本地存儲,在搜索按鈕點擊之后先獲取本地key為history的數據,如果存在將該數據轉換為數組,將此時搜索欄中搜索的關鍵詞push進當前數組,然后轉換為字符串存儲在本地,如果本地沒有key為history的數據那么直接將此時的關鍵字存到一個數組里,轉為字符串形式存到key為history的本地存儲中。
onNavigationBarSearchInputConfirmed(e) { //原生導航欄軟鍵盤搜索
//本地化搜索歷史
var _this = this;
uni.getStorage({ //獲取本地數據
key:'history',
complete:function(res){
if(res.data){ //如果本地數據存在
var arr = JSON.parse(res.data);
arr.push(e.text);
_this.historyList = arr;
uni.setStorage({
key:'history',
data:JSON.stringify(arr)
})
}else{ //如果本地數據不存在
var arr = []
arr.push(e.text);
_this.historyList = arr;
uni.setStorage({
key:'history',
data:JSON.stringify(arr)
})
}
}
});
}
5. 存在的問題
5.1 頂部選項卡問題
公眾號,項目,體系二級頁面,都使用了頂部選項卡來完成這部分的功能,但是體驗效果確實不好,有時候數據加載慢的時候已經切換到下一個選項卡,數據還沒有加載過來,依然顯示上一個選項卡的數據,體驗很不好。
5.2 uniapp存在的一些問題
不知道是不是我使用方法的問題,uni.$on()監聽到事件之后有時候會不執行下面的邏輯,很奇怪這個問題查了很久,沒有找到問題。
5.3 登錄注冊input框聚焦問題
聚焦時不能上推頁面,也就是說,軟鍵盤會遮擋input輸入框,按照官方文檔,設置必要的選項但是沒用,我下載了hello uniapp官方體驗版,也存在這個問題。
5.4 第一次打開App卡頓問題
第一次打開App,切換到公眾號,項目,導航時會非常卡頓,得等很長時間才能流暢運行,第一次切換之后就好多了。收藏也是,第一次在某個列表收藏某個文章時,會明顯感到很慢,之后就會好點了。
5.5 nvue使用問題
nvue采用weex基于原生引擎的渲染,體驗與渲染效率比較好,但是在使用過程中踩了不少坑,因為之前沒有使用和研究過weex,所以連最基本的樣式剛開始都寫不順,如果使用熟練了weex寫起來也很方便。比如文本只能最好寫在<text>組件里,而且文字與text標簽不能換行排列,否則用過你就知道了哈。
點擊到weex官網
5.6 安裝包體積比較大
大概37M左右,還是比較大的。
先寫這么多,以后有想起來的需要補充的定期補充一些內容。
最后真的很感謝鴻洋大神提供的開發api,與他的安卓開發社區,項目中的所有api均來自www.wanandroid.com網站純屬學習交流使用,不得用于商業用途。點擊到玩安卓社區
最初看到很多人在鴻洋大神的鼓勵下,去使用kotlin,flutter,reactNative,java等去開發玩安卓app,自己也很羨慕,也就誕生了自己開發的念頭,但局限于自己技術原因,因為前期接觸過dcloud其他產品,所以開始學習了解使用uniapp去開發了這個安卓版本的《玩安卓App》
還要感謝uniapp官方以及該框架使用者,在開發過程中,在社區提出很多問題,有很多問題都得到了解決,并且還推薦了不少相關文檔與知識。我是一名前端開發代碼搬運工,等到有機會學會了reactNative 和 flutter,有機會還想使用flutter 和 reactNative再開發出自己的App。體驗不同的體驗。
玩安卓社區還有很多優秀的開源的kotlin,flutter,RN等開發的各種版本的玩安卓,有興趣的大家可以自己去體驗。
以上都是開發過程中遇到的問題和一些總結。
歡迎大家多多交流學習。轉載請注明出處。
項目源代碼地址:https://github.com/Mstian/wanAndroid
項目博客地址:http://www.lxweimin.com/p/1557569e1b15
項目下載地址:https://www.pgyer.com/pv0D
邀請碼4566
——————————————————————————————————————————
2019-12-6更新
增加功能:
1.分享文章:
客戶端支持分享文章,分享的文章可以在登錄狀態下我的文章列表查看。(暫無刪除功能,后續會補上);
2.查看我分享的文章列表:
——————————————————————————————————————————
2019-12-12更新
增加功能:電視直播
在uniapp中對于App端的直播也就是實時音視頻播放,不用live-player,而是直接使用video組件;
具體語法如下:
<video id="myVideo" src="https://dcloud-img.oss-cn-hangzhou.aliyuncs.com/guide/uniapp/%E7%AC%AC1%E8%AE%B2%EF%BC%88uni-app%E4%BA%A7%E5%93%81%E4%BB%8B%E7%BB%8D%EF%BC%89-%20DCloud%E5%AE%98%E6%96%B9%E8%A7%86%E9%A2%91%E6%95%99%E7%A8%8B@20181126.mp4" @error="videoErrorCallback" :danmu-list="danmuList" enable-danmu danmu-btn controls>
</video>
video組件具體屬性配置請移步https://uniapp.dcloud.io/component/video
有關RTMP、RTSP、HTTP視頻協議詳解請移步https://www.hangge.com/blog/cache/detail_1325.html
2019-12-13更新
說明:每次更新是重新打了一個包,但是下載地址不變,之前有下載過App的如想體驗新功能,需要重新下載一個安裝包。
今天看到有開課吧分享給我的vue視頻,有關源碼解析的,大致看了一下感覺不錯,放到App里面的,入口在我的-vue視頻里面。
寫在最后:文中內容大多為自己平時從各種途徑學習總結,文中參考文章大多收錄在我的個人博客里,歡迎閱覽http://www.tianleilei.cn