框架升级记事

2019-07-28  本文已影响0人  大乔是个美少女

升级原因:
我们现在一直维护的项目是一个angularjs的老项目,前端技术发展的很快,而且angular已经不向下兼容了。
https://segmentfault.com/a/1190000013258094
技术框架比较老旧,热更新、组件化……很多可以方便我们开发的工具都没法使用。
新框架,提高开发效率。
迁移方向:
迁移到vue的技术栈上,和angularjs的数据绑定比较相似,又有组件化等一些新的特性。
迁移成本低。
方案选择:
老的项目开发维护3年,整体功能效果都比较好,如果全部迁移vue,重写成本高,周期长,回报低。
angularjs内嵌vue项目功能。
1)ngvue
angularjs使用ngvue,将vue封装为angularjs指令。
尝试功能效果详见:使用ngvue开发可视化查询功能
2) iframe
vue + element UI
内外通信:sendMessage

    # 向父窗口发送消息
    sendMessageToParent: (action, data) ->
        window.parent.postMessage({action, data}, '*')

    message_event_name = 'message.iframe_vue onmessage.iframe_vue'
    scroll_event_name = 'scroll.iframe_vue'

    $(window)
        # 监听 iframe 高度变化后,自适应
        .off(message_event_name).on message_event_name, (e) ->
            # 如果已经不在 iframe 页面了,就注销监听
            if not hasIframeVue()
                return $(window).off(message_event_name)

            {action, data} = e.originalEvent.data
            $timeout ->
                switch action
                    # 设置 iframe 高度,自适应
                    when 'set-height'
                        {height} = data
                        # 最小为屏蔽高减去顶部 header
                        min_height = screen.height - $('.page-header-v2').height()
                        height = Math.max(min_height, height)
                        page_content = $('.page-container .page-content')
                        getIframe().add(page_content).css({height, minHeight: height})

    # 与 iframe 子页面通信
    getIframe = -> $('#iframe-vue')
    sendMessageToIframe = (action, data) ->
        getIframe()[0].contentWindow.postMessage({action, data}, '*')

    # 监听父窗口发来的消息
    onParentWindowMessage: ->
        window.addEventListener('message', (e) =>
            {action, data} = e.data
            Vue.nextTick =>
                switch action
                    # 监听父窗口的获取localStorage的值,存到 iframe 的localStorage中
                    when 'init'
                        {storage} = data
                        for key,value of storage
                            localStorage.setItem(key,value)
        )

问题:
vue 单页路由切换无法保存路由信息,浏览器回退失效?无法复制访问路径。
解决方案:将iframe页面路径在路由跳转完成后,更新到父页面的URL上。
当URL重新访问时,修改iframe src地址。

# 跳转后
router.afterEach (to, from) ->
    addPathToURL(to, from)

addPathToURL = (to, from, next) ->
    params = (new URL(document.location)).searchParams
    before_url = params.get("path")
    if not before_url? || before_url.indexOf(to.path) == -1
        data =
            name: to.name
            url: to.fullPath
        utils.sendMessageToParent('change-url', data)

# 修改URL
when 'change-url'
    {name, url} = data
    params = new URL(location.href).searchParams
    path = decodeURIComponent(window.atob(params.get("path")))

    if path.indexOf(url) == -1
        new_url = "#{url}"
        new_url = "#{location.pathname}?path=" + window.btoa(encodeURIComponent(new_url))
        document.title = name + ' | 云窗'
        # window.history.replaceState("" , "", new_url)
        $location.url(new_url)
        $location.replace()
        # $window.history.pushState(null, 'any', $location.absUrl())
        #强制刷新更新页面URL
        # location.replace(new_url)

当时遇到一个比较烦恼的问题是:在更新URL的时候,location.href赋值会导致页面强制刷新,单独使用pushState和replaceState的时候都会不同程度的加入浏览路径到浏览器历史存储的栈里,影响正常回退效果。
最后,感觉可能是父页面的angularjs的路由变化会加入到浏览器历史存储的栈里,https://stackoverflow.com/questions/22914228/successfully-call-history-pushstate-from-angular-without-inifinite-digest
更新后,成功。

image.png
    if location.search.indexOf('?path=') > -1
        _host = host.replace('/yunchuang-vue/views', '')
        params = new URL(location.href).searchParams
        path = decodeURIComponent(window.atob(params.get("path")))
        url =_host + path
        console.log url
    else
        # 添加一个随机数,防止缓存
        url = host + iframe_url_lut[$state.current.name]

        symbol = if url.indexOf('?') > -1 then '&' else '?'
        url = "#{url}#{symbol}r=#{Math.random()}#{new Date().getTime()}"

需要注意的地方是:子页面向父页面传递URL,拼接在父页面的URL时,浏览器会对特殊字符进行编码,导致匹配的时候,也需要对path解码。有时候处理search路径时,search内容长度长,内容为中文,编码后的长度会超过浏览器显示的长度,显示效果不好。decodeURIComponent(window.atob(params.get("path")))window.btoa(encodeURIComponent(new_url))所以我们对path进行了手动编码后base64处理,显示效果更友好。

后续问题:angularjs路由不变更,点击router不变化,代码更新为:

    if $stateParams.path
        _host = host.replace('/yunchuang-vue/views', '')
        path = decodeURIComponent(window.atob($stateParams.path))
        url =_host + path
    else
        # 添加一个随机数,防止缓存
        url = host + iframe_url_lut[$state.current.name]

        symbol = if url.indexOf('?') > -1 then '&' else '?'
        url = "#{url}#{symbol}r=#{Math.random()}#{new Date().getTime()}"

 if path.indexOf(url) == -1
     document.title = name + ' | 云窗'
     path = window.btoa(encodeURIComponent(url))
      # $location.url(new_url)
      # $location.replace()
      $state.transitionTo($state.current, {'path': path}, {notify: false})
上一篇下一篇

猜你喜欢

热点阅读