背景

最近看上了ElementUI(Vue实现)用来实现一个管理系统Demo,其中一个最常见的需求就是左侧导航不动,右侧主页块在点击导航菜单时动态更新,如下图所示:

java 渲染vue页面 java web vue_java


之前的实现方案是右边嵌入一个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,有更好的解决方案请留言。


转载于:https://blog.51cto.com/13802307/2295963