1. 程式人生 > >在Java Web Project中實現Vue異步組件加載

在Java Web Project中實現Vue異步組件加載

ati 解析器 webapp ast 文件 要求 dir win sha

背景

最近看上了ElementUI(Vue實現)用來實現一個管理系統Demo,其中一個最常見的需求就是左側導航不動,右側主頁塊在點擊導航菜單時動態更新,如下圖所示:
技術分享圖片
之前的實現方案是右邊嵌入一個iframe,動態更改iframe的url即可,現在既然用了Vue咱也試試單頁,是不是顯得更優雅。接著就接觸到了vue-router、組件、異步組件這些關鍵字,本以為把頁面定義為xxx.vue放到webapp下,然後告訴vue-router去加載就好了,最後發現自己想簡單了,思維模式還停留在Java Web開發上,感覺Vue這類框架更多適用於純前端開發者或Node環境?按照官方文檔的說法“結合 Vue 的異步組件和 Webpack 的代碼分割功能,輕松實現路由組件的懶加載。”在 Webpack 的加持下貌似可以達到要求,但是這又是一個什麽鬼?暫時粗淺的認為它是一個工具,可以解析.vue生成.js。難道說我要把前端部分單獨出來,然後每次寫完先 Webpack 一下,再把生成的文件拷貝到webapp下?這對於目前的模式來說肯定是不可行的,且不說前後端分離帶來的部署調試的麻煩,首先分離後就喪失了Spring+Thymeleaf的優勢,其次目前的情況分不分都是一個人玩,從前寫到後,切來切去多累,我只想在一個Eclipse 的 Project 中解決問題,怎麽辦?

實現思路

後來研究了Vue的異步組件,發現它要的無非就是一段定義組件的JS代碼,那麽完全可以定義一個接口來輸出JS代碼。把一個Vue組件拆分成兩個同名文件如:user_list.js user_list.html(user_list就是組件名稱,本來一個js就足夠了,但是為了避免在js中寫HTML字符串還是分開好,js中的template屬性用一個占位符便於替換如:template: ‘$template‘)放在WEB-INF/vue-component下,然後實現接口,這個接口收到請求自動把兩個文件拼合為一段JS代碼,響應給前端,代碼如下:

@GetMapping("/vcp")
public void parse(@RequestParam("p") String path, HttpServletRequest req, HttpServletResponse resp) throws IOException {
    if(StringUtils.isEmpty(path)) return;
    String res = "null";
    String vcpDir = req.getServletContext().getRealPath("/WEB-INF/vue-component/");
    File jsFile = new File(vcpDir + path + ".js");
    File htmlFile = new File(vcpDir + path + ".html");
    if(jsFile.exists() && htmlFile.exists()) {
        String jsCode = BaseUtils.readCodeFileAsText(jsFile);
        String htmlCode = BaseUtils.readCodeFileAsText(htmlFile);
        res = "window.vcpRes[‘"+path+"‘] = "+jsCode.replace("$template", htmlCode);
    }
    // response
    resp.setContentType("application/x-javascript;charset=utf-8");
    PrintWriter out = resp.getWriter();
    out.println(res);
    out.close();
}

接口定義好了再來看Vue部分(下面給出關鍵性代碼,關鍵是思路,版本信息:vue2.5 vue-router3.0)

// 定義全局變量,用於接收接口輸出的JS組件對象
window.vcpRes = {};

// 添加路由
routes.push({path: ‘/user/list‘, component: Vue.component(‘user-list‘, syncComponent(‘user_list‘)) });

/**
 * 該函數通過JQuery異步獲取組件,path參數就是組件名如:user_list
 */
function syncComponent(path){
    return function(resolve, reject){
        $.getScript(‘vcp?p=‘+path, function(){
            var component = window.vcpRes[path];
            if(component){
                resolve(component);
            }else{
                reject(‘組件加載失敗:‘+path);
            }
        });
    };
}

結語

如果有時間,也可以在接口中實現一個.vue的解析器,這樣組件就不用分兩個文件寫了。這只是我個人能想到的一種解決方案,能力有限。如果你是一名Java Web開發者也在使用Vue,有更好的解決方案請留言。

在Java Web Project中實現Vue異步組件加載