美文网首页高级js用法
将现有传统的php网站项目迁移到vue-cli上

将现有传统的php网站项目迁移到vue-cli上

作者: 王浩然5555 | 来源:发表于2019-06-24 10:44 被阅读1次

    这是一个复杂的工程,但是每一步都是可寻的。所有迁移过程步骤都是可运行的,

    本人实践的是一个电子表格项目

    为大家提供一个平滑迁移的策略框架

    https://github.com/13601313270/tableHub

    真个迁移过程的第一次提交开始于Nov 7, 2017

    https://github.com/13601313270/tableHub/commit/7b558d89931d627384d6e3c98fd435316ff61b74

    先说一下我的现状

    这是一个传统的php网站,用php的smarty模板将变量打到模板文件,生成对应的html。js采用的是传统的es5的js代码,在html的head头部引入

    image

    无论用什么主流还是不主流的框架,传统的php网站都是这个套路,新建一个页面对象,然后通过php添加很多个变量给smarty,然后让smarty去fetch模板文件,将变量和模板结合生成html

    再来看一下模板文件

    image

    对smarty的前置过滤器做了优化,最终的html中站内js会有合并成一条js引用,顺序依照模板js顺序,不会破坏依赖关系。然后js进行压缩。但所有的js是用es5写的,smarty的include实现的组件,真的只是html拼接上,无法实现vue组件的变量传递。经常会组件生命全局变量污染变量。

    有很大的工作量需要做,前后端分离是个大过程。

    第一步,将所有的smarty变量输出点,改用ajax请求来输出。

    然后在主html尾部增加一个请求这个地址的代码。

    这个请求需要带上网址中的所有参数,比如下面,我们就带上了fileId参数

    image

    可以新建一个独立php文件,用于接收ajax请求,返回数据,改造成一个同样返回值的json对象。

    image image

    生成一个有style,data,isMyTable属性的对象并生成json。

    接下来就是细心的时候了,去找所有用到变量的地方,改为用js去实现

    所有引用tpl。(如果不保证tpl只被这一个变量调用。可以新建一个同名代后缀的组件tpl。比如tools.tpl可以新建一个tools.state.tpl)。

    我们以isMyTable变量举例,isMyTable为true的时候有一个editChange样式的div节点

    image

    我们改造为,先将这个元素隐藏,js判断如果为真,改为显示,否则移除dom

    image image

    接下来我们就得到了一个可运行,跟原有功能一致的改动,这是一个平滑的改动,即使发布到线上也不会有bug(只不过会多增加两倍的服务接口请求)。可以commit一下代码到本地分支了。

    接下来循环执行这个辛苦的事情,我们检查主模板和组件的模板,将所有使用变量的地方,改为js来实现功能

    比如smarty的foreach循环改为js的for循环添加dom

    在自己完全确认已经没有模板文件使用php传递进来的变量后,最好再用编辑器的文件查询功能,查询一下isMyTable,tableStyle,tableData,title这几个字符串,验证一下是否还有遗漏的。

    然后我们就可以删掉传递的数据逻辑,控制器精简为下面的样子。

    image

    这时候模板文件所有的动态数据,都是通过ajax请求拼接好的。

    在经过自测,可执行后。最好再增加一些双保险

    例如由测试工程师系统化测试,小比例用户灰度测试等。之后就可以安全的大范围上线了。

    其实现在依然还是用的smarty,还会存在比如include等smarty方法。这么做的意义,是首先摆脱php请求数据来赋值hml的依赖,为以后前后端分离做好第一步。

    image

    组件迁移

    将组件需要使用的函数定义放在<script></script>中,将执行的语句,都放到mounted之中,因为只有在mounted的时候,组件的dom才存在于document里。先忽略语句是不是使用es6语法,直接加进去。最起码是可以保证代码是可以运行的。

    迁移前

    image

    迁移后

    image

    迁移通用js方法,循环找每一个在index.html里使用的全局js的方法,

    每个方法,单独做一个es6的js。然后将所有使用原有js的组件,都迁移到新js,因为所有组件都已经是使用工程化编写了。等所有调用这个js都已经改为工程化引用新js后,删除index.html的老引用。

    慢慢的,index.html的js会越来越少,慢慢就没了

    image

    全局函数提取到单独的js文件中,用es6的写法

    image

    所有使用这个函数的模块,都通过引用来调用

    image

    最后删除原始的定义

    到这为止得到了一个混合项目,既可以将后面的项目进行新式的vue开发,老的逻辑维持现状,将来会遇到很多针对某个模块的需求,或者某个模块的bug,这时候,很有可能被开发人员顺便的迁移到新方式。

    但是因为代码相互依赖,一个jquery的点击事件,内部封装了若干jquery的操作,以至于代码不会纯粹到可以迁移而不去影响别的逻辑。所以即使过了很长事件,有可能依然被迁移的不多。

    这时候,我建议先针对dom输出的逻辑进行迁移。因为这种代码执行起来最容易,不会影响太多的其他代码。

    image

    针对这种情况代码,可以改为用vue的v-for优先迁移。

    攻坚战

    排在第二种优先级的是这种将状态保存在dom属性上的逻辑,因为这种逻辑本身就是过去代码策略的失败。当很多属相都迁移到data上的时候,剩下的代码才更好迁移。但是这一块也是最容易遗漏的。后面我在使用中,尝试总结平滑迁移技巧。

    image image

    这时候将dom属性改为使用vue的data迁移,变成了一个很危险的大工程,因为很容易拉下部分写入或者调用的场景,因为调用这个属性的地方,可以遍及很多个文件,所以不能想当然的以为当前文件都迁移了,就是安全了。这时候我们可以先拿写操作入手。

    第一步修改本文件内所有的将所有修改这个dom属性的地方同时写入一个data。commit一下,因为这个环节是“安全的”,就是说拉下一个两个的,也不会有任何bug,因为没有任何地方使用这个data

    image

    下面整个项目搜索一下,尽可能找到所有使用这个dom属性的地方。如果没有,则不用进行下面这一段的步骤。直接进入下一段监听环节

    如果有则

    因为vue的data作用于在本文件中,所以别的模板文件修改dom属性,我们没办法做到同时修改这个data,我们增加一个队data的监听,当data变化的时候,同时修改dom的属性

    image

    在所有使用这个组件的page中,增加一个vue的data,例如取名为child_props1,然后作为参数,组件调用的时候传递给组件。可以commit一下,因为这一步也是安全的。

    如果加载插件的页面有修改dom属性,则额外增加一个修改child_props1的逻辑。

    如果页面加载的其他组件修改了dom,则在所有修改属性的地方,额外增加一个事件来出发这个回调。

    image

    然后在page中监听这个事件,然后修改data。

    可以将时间以temp_开头,用以说明是迁移过程中临时产生的。当然如果你认为这个值确实应该是页面全局的,也可以不加temp_

    可以commit一下,因为到这也是安全无bug的

    监听环节

    当然,有可能拉下了一些修改dom属性的地方。

    这时候,我们在组件某个使用属性地方加一个检测

    image

    我们只用在部分,或者1个最常用的地方,加上检测。保证能覆盖所有用户访问情况即可。当与预期不一致的时候进行一定的日志,或者输出到控制台。

    这个检测的过程可以是:

    测试工程师规范化的普测,然后监听控制台。

    也可以是用户大量测试,然后发送日志给服务器。休息一会干点别的事情,一个小时后再来看看日志

    可以发送当前url,或者其他信息。

    等保证了所有修改dom的属性的地方都有覆盖到的时候,则去掉所有的修改dom属性的代码。

    这个过程,可以去掉一个,测试一个。

    去掉一个,测试一个。

    等所有都去掉后,commit一下。

    再次进行一次普测,如果没有再收到不一致报警。则可以安全的去将组件内所有调用dom属性的地方,改为取data值。然后commit

    然后去掉组件内的watch修改dom属性的逻辑

    image

    这时一个安全的迁移已经完成了。

    将写在body中和写在js中的函数迁移到vue的method中,一个很大的坑,就是this变量。vue的method中的this代表的是vue对象。所以,不要讲包含this的函数随意迁移进method。

    除非发现这个函数所有的调用,都已经在vue结构内部,否则你把这个函数迁移进去,所有调用方都将找不到。

    但是反过来说,所有对旧函数的调用代码都迁移到vue内部,但是函数在外部并不会造成任何的bug。所以函数的迁移永远是靠后的。

    优先迁移这种执行形代码,这种代码处于依赖链头部。就像下面这一段,它依赖selectTd函数,但是没有任何代码依赖它。

    这种典型的jquery项目的事件绑定,进行若干步骤,迁移进vue里

    image

    首先将this提取,vue项目的this是一个和jquery的this格格不入的东西。改成一个中间变量来代替this。

    image

    可以commit

    这时候我们找到绑定这个事件的受体#tablePanel,在上面添加一个vue的对应事件,jquery的事件是click,所以增加一个vue的@click

    image

    需要传入$event参数,下面我们在methods中创建一个函数

    image

    我们在methods中创建对应一个函数

    jquery的on事件委托的dom节点是满足选择器.edit #myTabContent td的

    我们通过下面的逻辑,实现跟jquery一样的逻辑,找到委托节点

    [ 复制代码

    ](javascript:void(0); "复制代码")

    <pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">if ((event.target).is('.edit #myTabContent td')) { var **eventDom** = event.target; } else { var **eventDom** =(event.target).parents('.edit #myTabContent td'); if (eventDom.length === 0) { return;
    } else {
    eventDom = eventDom[0]
    }
    }</pre>

    [ 复制代码

    ](javascript:void(0); "复制代码")

    接下来,我们就可以把执行内容部分,copy到刚刚新建的函数里了。

    image image

    然后删除之前的这一段jquery方式的事件绑定,防止执行两次。就可以执行测试去了。

    测试通过,进行commit。

    虽然这个代码最终内部依然使用了jquery,但是他的意义在于,为类似selectTd这样的函数迁移进vue内部扫清障碍。是个中间步骤。

    等待越来越多的这样执行被迁移,你会发现有很多的全局变量和全局函数,都是只被vue内部调用。这时候就是他们可以迁移的时候了。

    这种方式可以迁移click,但是迁移用on绑定的mouseenter的时候,需要注意改为mouseover事件,否则,每一次的进入都是以整体才能捕获到。

    image

    配合使用刚刚的click的方法,可以捕获到真正想绑定的选择器dom,但是会有重复出发的情况出现,我们在某一个【.edit #myTabContent td】里移动会一直出发mouseover,这时候我们需要加一个记录,只有变化了另一个td,才去出发后面的执行,否则return掉。

    [ 复制代码

    ](javascript:void(0); "复制代码")

    <pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">methods: {
    lastEnterTd: '',//用于记录最后一次出发的dom
    mouseenter_temp(event) { if ((event.target).is('.edit #myTabContent td')) { var eventDom = event.target; } else { var eventDom =(event.target).parents('.edit #myTabContent td'); if (eventDom.length === 0) { return } else {
    eventDom = eventDom[0]
    }
    } // 防止重复出发
    if(this.lastEnterTd === eventDom){ return;
    }
    this.lastEnterTd = eventDom; //要执行的逻辑
    console.log(eventDom);
    }
    }</pre>

    [ 复制代码

    ](javascript:void(0); "复制代码")

    大的方针,就是会有很多个中间状态,中间状态也许会有很多旧的方式。但是只要这个中间状态能为后面的迁移打通障碍,就值得去做。就像华容道一样,理解了这个初衷,那么这个步骤就是成功的,所以就不在继续优化这个函数内部,就到这就暂告一段,日后自然还有机会去优化。

    下面进入了漫长而无法推动

    中间态的代码有若干特点。项目被vue化了,但是项目内部有很多函数会执行jquery的方法。比如下面这个

    image

    这时我们可以将vue和jquery的夹缝处改为使用原始的js的dom来作为交互接缝。因为vue和jquery都支持dom的读写操作

    image

    vue组件是支持嵌套组件的,所以使用dom来间接操作vue的虚拟元素,肯定不是最终态。但是vue组件嵌套需要修改被嵌套和嵌套都改成vue组件才能执行。被嵌套的子组件有可能内部还有子组件。所以就会演变成需要“同时”把所有地方都修改为vue组件,这是不可能安全的被推动的。

    所以通过dom来间接修改,可以保证可以一个一个一个一个的去逐步攻克所有的组件。

    通用js全局变量然后

    摆脱jquery,

    摆脱jquery的路上有一堆障碍物,这些障碍物叫做jquery插件。我们可以寻找替换的vue插件,或者用vue的方式替换这些插件。

    比如我的项目中使用了dragging插件,就是可以拖动dom的,我可以自己去写鼠标事件来去掉使用dragging插件

    image

    比如我实现了一个vue的拖动插件

    image

    相关文章

      网友评论

        本文标题:将现有传统的php网站项目迁移到vue-cli上

        本文链接:https://www.haomeiwen.com/subject/dfrnqctx.html