vue使用之剑走偏锋——菜单组件篇
背景
习惯了这样的写法了,上来先来一个背景,交待一下事情的起因。事情的起因很简单,用惯了mvc框架,想来一发前后端完全分离的框架试试。选用的人员和技术是这样子的,让原本做java的web开发的人员使用vue,在visual studio code里面写纯前端的代码,然后由.net的同事,提示webapi2的接口。关于这个设计中的权限验证等问题,会单独一篇笔记进行介绍。
这里要说的是,由于前后端分离,导致没有了后台的java模板或者.net的razor之类的视图引擎。没有了这种东西会很尴尬,因为需要用ajax来获取数据,获取到数据之后呢,用jquery的选择器选择dom然后一个个填充,提交的时候再用jquery的选择器选择dom取其值——。这样子的话,估计我要被同事们骂死……。为了邻里和谐,我觉得vue比较流行,而且它的mvvm据说速度不错,试用了一下,觉得简单方便条条框框少,毕竟我只是要用它的mvvm功能,只是为了把对象与dom绑定,把事件相绑定。
单面(SPA) vs 多页
这个是我比较头疼的问题,其实个人比较倾向单面应用,因为直观上觉得虽然第一次要加载的东西比较多,但是,由于浏览器有缓存以及做好载入界面,用户其实是容易接受的。而多页面每次都要加载许多东西,虽然也有缓存,但是许多对象都需要初始化,直觉上就知道总的性能不如单页应用。然后我就开始搭建vue的spa了,用了vue的webpack模板,搭建出来的项目如下:
由于使用的工具是vscode,所以,输入命令,调用bower,npm等还是比较爽的,而且可以直接开发了。但是,我发现,我想使用的是一个开源的基于bootstrap的后台管理系统模板,这个模板相互依赖特别多,我理了半天,没理清楚,更别说把它做成vue的组件化了。没过多久,我就放弃了这条我其实比较喜欢的路。
放弃了spa,选择了多页,但是,多页又带来了另外一个问题,就是是用iframe将菜单、导航等独立在外以便共用,还是每个页面都带一个菜单、导航。
iframe VS 纯多页
公司的项目一直都是在使用iframe,但是,这次的项目有个明确的要求,就是要自适应布局,要能在手机上无缝转换,这个,就是我很不放心iframe,我试着将iframe放在bootstrap自适应的布局中,确实也可以很好的进行工作,但是,总觉得有一天它无故导致出现滚动条,无故导致某些东西展示不全。同时,它还有一个致命的问题,就是模态弹窗只能遮住iframe,而非整个浏览器页面,这就很头疼。这样用户的操作流程就是开放性的了,很难摸清楚用户的实际操作流程,会导致什么意外的情况发生。
所以,最后,只能用纯多页的了。
纯多页的前端
纯多页其实也存在一个问题,就是上面所说的,共用区域在每个页面里面都要写一次,其实,头部导航、左边菜单,还是很烦的,加上没有后台帮助渲染,前端的代码少不了。所以,我自己写了一个方法,用来将其它的html页面加载至当前界面的当前位置,其实类似于include。
function HtmlInclude(url) {
var req = false;
// Safari, Firefox, 及其他非微软浏览器
if (window.XMLHttpRequest) {
try {
req = new XMLHttpRequest();
} catch (e) {
req = false;
}
} else if (window.ActiveXObject) {
// For Internet Explorer on Windows
try {
req = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
req = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
req = false;
}
}
}
if (req) {
// 同步请求,等待收到全部内容
req.open('GET', url, false);
req.send(null);
document.write(req.responseText);
} else {
document.write("对不起,你的浏览器不支持" +
"XMLHTTPRequest 对象。这个网页的显示要求" +
"Internet Explorer 5 以上版本, " +
"或 Firefox 或 Safari 浏览器,也可能会有其他可兼容的浏览器存在。");
}
}
调用的方法如下:
这样,在
<script>
HtmlInclude("snip/menu_left.html");
</script>
的位置,最终就会变成"snip/menu_left.html"中的代码,简单完美!但是,在后面的调试过程中发现,浏览器中根本无法调试"snip/menu_left.html"中的代码,这就很尴尬了~~~
vue组件的剑走偏锋
vue的组件化提供了相当牛逼的特性,但是,对于单文件的支持非常地不行,只能在webpack等“编译”功能的前提下,才可以使用.vue文件之类的组件单文件模式。但是,公司内部其实连html,css,javascript是非常模糊,让一下子跃过html,css,js直接去用webpack编译,估计不仅调试起来让人崩溃,甚至连开始都开始不了。所以,咱们还是从实际出发,以html为骨骼,以css为皮肉, 以javascript为筋脉。
查阅了一下,vue提供了另外两个模式的方式,其一是内联模板,这种内联模板其实是让组件的调用者给予组件的template内容,这相当于在每个页面里面都要把对应的组件的模板写一遍,与我们的需求不符。其二便是X-Templates,这个东西与我们需要的功能类似。它将template内容单独写成html格式的js文件,然后可以通过<script type='text/x-template' src='' id''>去加载,在之后再加载与之对应的组件js文件,并在组件的template处写上面那个x-template标签中的id。这下又尴尬了,每个组件的引用必须引用两个文件,而且还分先后,并且,引用模板的js文件时,需要特殊指定type,同时,因为是js文件,编辑器对html提示功能就瞎了。所以,vue内置的这两种模式并不适合我。
我的方案
可能是经历的原因,我觉得,我的任何项目里面都要有jquery,虽然vue提供了ajax的请求插件,但是,我依然觉得有必须引用一下jquery,有了它,我才有安全感,客户的各种奇葩需求,我心中才有底,不然今天动画,明天校验的,我能给愁死。
于是,我做了另外一个打算,既然
Vue.component('my-component', {
template: ""
});
我给template这个对象字符串,而我又想给它的是html页面,那么我用jquery请求就是喽,如下:
Vue.component('my-component', {
template: $.getSync("templates/com1.html")
});
这样子的话,我只需要在templates文件夹中增加这个com1.html,供vue使用即可。这个$.getSync是我实现的一个jquery的扩展方法,因为jquery的同步请求只有$.ajax中才有,而且还是要通过回调,$.get方法是异步的,除非设置全局同步,全局同步会影响其它的功能代码,所以,万船无奈自己用$.ajax封装了一个$.getSync方法。
jQuery.extend({
getSync:function(url){
var result=null;
$.ajax({
url:url,
async:false,
success:function(data){
result=data;
}
});
return result;
}
});