mui初級入門教程(七)— 基於native.js的文件系統管理功能實現

文章來源:小青年原創
發佈時間:2016-08-01
關鍵詞:mui,nativejs,android
轉載需標註本文原始地址: http://zhaomenghuan.github.io...javascript

前言

這段時間以來一直有人問5+ sdk怎麼在原生中集成,每次給了文檔和沒給沒啥大區別,這部分人之因此不能根據文檔寫出想要的結果,無非有兩種狀況,一種對於原生徹底懵逼,畢竟基於mui作APP畢竟前端仍是佔多數,而前端中熟悉原生的人畢竟是少數,不少人聲稱會原生哪裏還會用h5,這話只能呵呵?就大趨勢而言,應用web化是如今的潮流所向,如今即便有資金和技術實力的大廠也在作混合式開發和H5的APP,否則dcloud官方也不會花大力氣在流應用上。近來愈來愈多的原生開發者朋友和我交流h5,他們不少是被逼着轉前端,這些人懂原生,可是不懂h5,因此這些朋友從原生轉mui過程當中可能仍是不可以理解若是用5+ sdk,中間的交互怎麼解決,這就是第二種人的困境?css

正是基於這種現實窘境,我打算把本身只知其一;不知其二的android開發經驗從新拿起來,試着去寫點什麼,拋磚引玉,僅此而已。本文做爲混合式開發的第一篇,暫時不會介紹離線打包集成5+ sdk的相關內容,先用nativejs練練手。html

步驟分解

在開始集成5+sdk以前,咱們先來用native.js寫一個文件管理的功能,以此熟悉native.js的相關API。先來預覽一下效果:
圖片描述前端

常常有人問使用5+怎麼系統文件,其實用nativejs就能夠實現,有人又要問nativejs怎麼引用。每次遇到這種問題,真的要噴血而出。html5

nativejs是集成在5+ app中,默認不須要引入就能夠直接引用。nativejs是經過js調用系統原生方法,從而實現5+標準中沒有說起的方法,因此說白了你仍是要會原生,或者有人用nativejs將原生的方法轉成了js,這樣你只須要在頁面中調用js的方法就能夠實現調用原生。nativejs在這裏充當一個「語法糖」的做用。java

對於這樣一個遍歷文件系統的功能,用原生方法寫,咱們會這樣寫:android

1.在AndroidManifest.xml下設置權限

<!-- 容許程序寫入外部存儲,如SD卡上寫文件 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>

5+ APP中這一步默認設置了,咱們不要管。git

2.導入Java類對象

import android.os.Environment;

Native.js中使用plus.android.importClass方法:github

var environment = plus.android.importClass("android.os.Environment");

3.判斷SD卡是否插入(涉及到SDK的讀取,最好先判斷SDK是否插入)

Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)

nativejs這樣寫:web

environment.getExternalStorageState() === environment.MEDIA_MOUNTED

4.得到sd卡根目錄

File skRoot = Environment.getExternalStorageDirectory();

nativejs這樣寫:

var sdRoot = environment.getExternalStorageDirectory();

5.遍歷sd卡根目錄下的全部文件和文件夾(返回值爲數組)

File[] files = sdRoot.listFiles();

nativejs中使plus.android.invoke調用對象(類對象/實例對象)的方法:

var files = plus.android.invoke(sdRoot,"listFiles");

6.過濾系統隱藏文件

import java.io.File;
import java.io.FileFilter;

FileFilter ff = new FileFilter() {
    public boolean accept(File pathname) {
           return !pathname.isHidden();//過濾隱藏文件
    }
};
File[] files = sdRoot.listFiles(ff);

nativejs中能夠這樣寫:

// 遍歷sd卡根目錄下的全部文件和文件夾
var files = plus.android.invoke(sdRoot,"listFiles");
var len = files.length;
for(var i=0; i<len; i++){
    var file = files[i];
    // 過濾隱藏文件
    if(!plus.android.invoke(file,"isHidden")){
        // 非隱藏文件執行操做
        
    }
}

上面的預覽效果能夠看出咱們對文件夾和文件進行了不一樣的操做,接着須要在遍歷中判斷。

7.文件及文件夾類型判斷

for(File file : files){
    if(file.isDirectory()){
        // 文件夾
    }else{
        // 文件
    }
}

nativejs寫法:

for(var i=0;i<len;i++){
    if(plus.android.invoke(file,"isDirectory")){
        // 文件夾
    }else{
        // 文件
    }
}

8.文件大小及單位轉換(這裏直接上nativejs版本)

// 讀文件大小
var FileInputStream = plus.android.importClass("java.io.FileInputStream");
var fileSize = new FileInputStream(file);
var size = fileSize.available();
// 單位轉換
var fileSizeString;
if(size == 0){
    fileSizeString = "0B";
}else if(size < 1024){
    fileSizeString = size + "B";
}else if(size < 1048576){
    fileSizeString = (size/1024).toFixed(2) + "KB";
}else if (size < 1073741824){
    fileSizeString = (size/1048576).toFixed(2) + "MB";
}else{
    fileSizeString = (size/1073741824).toFixed(2) + "GB";
}

9.建立文件夾與刪除文件(文件夾)

/**
 * 建立文件夾
 * @param {Object} path
 */
function creatFolder(path){
    var File = plus.android.importClass("java.io.File");
    var fd = new File(path);
       if(!fd.exists()){
           fd.mkdirs();
           plus.nativeUI.toast("建立成功");
    }
}
        
/**
 *  刪除文件(文件夾)
 * @param {Object} path
 */
function deleteFile(path){
    var File = plus.android.importClass("java.io.File");
    var fd = new File(path);
    if (fd != null && fd.exists()){
        fd.delete();
        plus.nativeUI.toast("刪除成功");
    }        
}

10.打開目錄和打開文件

咱們在打開目錄的時候,會遍歷該目錄下的文件夾和文件,實現方法同上面,打開文件咱們可使用5+ runtime openFile調用第三方程序打開指定的文件。

void plus.runtime.openFile( filepath, options, errorCB );

參數:

  • filepath: ( String ) 必選 打開文件的路徑
    字符串類型,文件路徑必須是本地路徑,不然會致使打開文件失敗。

  • options: ( OpenFileOptions ) 可選 打開文件參數

  • errorCB: ( OpenErrorCallback ) 必選 打開文件失敗的回調
    打開文件操做失敗時回調,返回失敗信息。

本文完整代碼:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <title></title>
       <link rel="stylesheet" type="text/css" href="css/mui.min.css"/>
       <link rel="stylesheet" type="text/css" href="css/circles.css"/>
       <style type="text/css">
           .loading {
               position: absolute;
               top: 50%;
               left: 50%;
               width: 200px;
            height: 200px;
            margin-top: -100px;
            margin-left: -100px;
            z-index: 9999;        
        }
        .loading .card {
            display: table-cell;
            text-align: center;
            vertical-align: middle;
            width: 200px;
            height: 200px;
        }
        .mui-backdrop {
            background-color: #15b5e9;
        }
       </style>
</head>
<body>
    <div class="loading">
        <div class="card">
            <span class="circles-loader">Loading&#8230;</span>
        </div>
    </div>

    <header class="mui-bar mui-bar-nav">    
        <h1 class="mui-title">文件系統</h1>
        <a id="add" class="mui-icon mui-icon-plus mui-pull-right"></a>
    </header>
    <div class="mui-content">
        <ul id="list" class="mui-table-view mui-table-view-chevron"></ul>
    </div>
    
    <script src="js/mui.min.js" type="text/javascript" charset="utf-8"></script>
    <script src="js/njs-io.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
        mui.init({
          gestureConfig:{
           longtap: true //默認爲false
          }
        });
        
        var mask;
        mui.ready(function () {
               mask = mui.createMask();//callback爲用戶點擊蒙版時自動執行的回調;
            mask.show();//顯示遮罩
        })
        
        var sdRoot = null;
        document.addEventListener("plusready", function(){
            init();
        }, false);
        
        // 渲染列表
        function init(){
            // 得到sd卡根目錄
            sdRoot = getSDRoot();
            // 遍歷sd卡根目錄下的全部文件和文件夾
            var files = plus.android.invoke(sdRoot,"listFiles");
               var len = files.length;
               
               var list = document.getElementById("list");
               var fragmentFolder = document.createDocumentFragment();   
               var fragmentFile = document.createDocumentFragment();   
            var li;
            for(var i=0;i<len;i++){
                var file = files[i];
                // 過濾隱藏文件
                if(!plus.android.invoke(file,"isHidden")){
                    var name = plus.android.invoke(file,"getName");
                    li= document.createElement('li');
                    li.className = 'mui-table-view-cell mui-media';
                    li.setAttribute('name',name);
                    
                    // 判斷是文件仍是文件夾
                    if(plus.android.invoke(file,"isDirectory")){
                        // 設置標誌爲文件夾,供後面使用
                        li.setAttribute('data-type', 'Folder');
                        // 讀取文件夾下子文件夾及子文件數目
                        var obj = readSonFilenum(file);
                        li.innerHTML = '<a class="mui-navigate-right">'+
                            '<img class="mui-media-object mui-pull-left" src="img/folder.png">'+
                            '<div class="mui-media-body">'+ name +
                            '<p class="mui-ellipsis">文件夾數量:'+ obj.subFolderNum + ' 文件數量:'+ obj.subFileNum +'</p></div></a>';
                        fragmentFolder.appendChild(li);
                    }else{
                        li.setAttribute('data-type', 'File');
                        // 讀文件大小
                        var fileSizeString = readFileSize(file);        
                        li.innerHTML = '<a class="mui-navigate-right">'+
                            '<img class="mui-media-object mui-pull-left" src="img/file.png">'+
                            '<div class="mui-media-body mui-ellipsis">'+ name +
                            '<p class="mui-ellipsis">'+ fileSizeString +'</p></div></a>';
                        fragmentFile.appendChild(li);
                    }
                };
            }
            list.appendChild(fragmentFolder);   
            list.appendChild(fragmentFile);  
            // 關閉遮罩
            mask.close();
            document.querySelector('.loading').style.display = 'none';
        }
        
        // 點擊打開文件
        mui('.mui-table-view').on('tap','li',function(){
            var name = this.getAttribute('name');
            var fileType = this.getAttribute('data-type');
            var filepath = sdRoot + '/' + name;
            if(fileType === 'Folder'){
                // 打開目錄詳細頁面
                mui.openWindow({
                    url: 'sub.html',
                    id: 'sub',
                    extras:{
                        name: name,
                          filepath: filepath
                    }
                })
            }else{
                // 打開文件
                plus.runtime.openFile(filepath);
            }
        }) 
        
        // 建立文件夾
        document.querySelector('#add').addEventListener('tap',function (e) {
            e.detail.gesture.preventDefault(); //修復iOS 8.x平臺存在的bug,使用plus.nativeUI.prompt會形成輸入法閃一下又沒了
            var btnArray = ['取消', '肯定'];
            mui.prompt('請輸入要建立的文件夾名:', '文件夾名', '建立文件夾', btnArray, function(e) {
                if (e.index == 1) {
                    creatFolder(sdRoot+"/"+e.value);
                } else {
                    plus.nativeUI.toast('你點了取消按鈕');
                }
            })
        })
        
        // 長按刪除文件
        mui('.mui-table-view').on('longtap','li',function(){
            var name = this.getAttribute('name');
              var btnArray = ['取消', '肯定'];
            mui.confirm('你肯定要刪除這個文件夾?', '刪除文件夾', btnArray, function(e) {
                if (e.index == 1) {
                    deleteFile(sdRoot+"/"+name);
                } else {
                    plus.nativeUI.toast('你點了取消按鈕');
                }
            })
        }) 
    </script>
</body>
</html>

原生文件操做

判斷SD卡是否插入

Environment.getExternalStorageState().equals(
android.os.Environment.MEDIA_MOUNTED);

得到sd卡根目錄

File skRoot = Environment.getExternalStorageDirectory();

得到私有根目錄

File fileRoot = Context.getFilesDir()+"\";

文件夾或文件夾操做

得到文件夾和文件路徑

  • 得到文件或文件夾的絕對路徑和相對路徑。區別:

String path = File.getPath();//相對
String path = File.getAbsoultePath();//絕對
  • 得到文件或文件夾的父目錄

String parentPath = File.getParent();
  • 得到文件或文件夾的名稱:

String Name = File.getName();

創建文件或文件夾

File.mkDir(); //創建文件夾
File.createNewFile();//創建文件

判斷是文件或文件夾

File.isDirectory()
File.isDirectory()

列出文件夾下的全部文件和文件夾名

File[] files = File.listFiles();

修改文件夾和文件名

File.renameTo(dest);

刪除文件夾或文件

File.delete();

這裏列出原生的經常使用方法,你們能夠根據須要進行實現。

後記

寫到這裏,本篇本應該繼續講講5+ sdk集成中的各類細節,可是想一想本篇做爲nativejs的開篇,先簡單介紹這個實例,讓你們根據須要本身實現或許更好,本文僅供參考。

文章最後仍是要放上文檔和本文詳細工程:

Native.js android API文檔
5+ App開發Native.js入門指南

Native.js示例彙總
本文詳細工程 njs-io

寫文章不容易,也許寫這些代碼就幾分鐘的事,寫一篇你們好接受的文章或許須要幾天的醞釀,而後加上幾天的碼字,累並快樂着。若是文章對您有幫助請我喝杯咖啡吧!
clipboard.png


近期在segmentfault講堂開設了一場關於html5+ App開發工程化實踐之路的講座,會講到5+ 開發中高性能的優化方案以及使用如何結合Vue.js進行開發,歡迎前來圍觀:https://segmentfault.com/l/15...

相關文章
相關標籤/搜索