Vue怎么做响应式布局

12,730 阅读2分钟

前言

本文讲述是从日常业务中总结而出的,不一定适合所有项目。毕竟每个公司或个人的项目不同,最佳实践也会有所不同。如果你可以从这篇文章吸收一些有用的东西,那么我很开心能够帮到你。但如果有问题的地方也欢迎大家积极吐槽指正

好了,下面进入今日主题

怎么做到响应式布局呢?
  • 首先我们得先了解什么是响应式 比较懒,就直接 拿来把你 image.png
  1. 响应式布局的优点: 面对不同分辨率设备灵活性强,能够快捷解决多设备显示适应问题。
  2. 响应式布局的缺点兼容性不好。兼容各种设备时工作量大,效率低下,代码累赘,会出现隐藏无用的元素,加载时间加长,其实这是一种折中性质的设计解决方案,多方面因素影响而达不到最佳效果,一定程度上改变了网站原有的布局结构,会出现用户混淆的情况

所以除非是后台管理系统这种比较灵活的服务端,其它的话响应式处理这方面做的较少

俗话说,天下文章一大抄。说实话,刚开始从产品经理那里结果需求的时候,我也很懵,以至于无从下手。
但是没吃过猪肉难道还没见过猪跑吗?
于是我想到了 AntDVueAdmin
不过,VueAdmin 这个官网链接貌似打不开了,就找到了它的国内源码地址供大家参考

演示效果

展示一下官网的效果截图 屏幕尺寸: <= 1200 它是介个样子 ↓↓↓ image.png

屏幕尺寸: <= 912 它是介个样子 ↓↓↓ image.png

屏幕尺寸: <= 768 它是介个样子 ↓↓↓ 这时候差不多就到移动端的适配页面了 image.png

内部具体实现的源码这里就不分享了,文件关联太多,展示起来说不完。主要还是懒

接下来。说一下我自己怎么实现的响应式布局思路。这里我只说Vue的

  • 第一步 首先想到就是 window.onresize 这个 API。 它可以监测窗口变化,是一个 BOM 对象
  • 第二步 先在 data选项里配置:screenWidth: document.body.clientWidth

然后在 window.onresize 方法里让 window.screenWidth = document.body.clientWidth
再让that.screenWidth = window.screenWidth

  • 第三步 当 窗口变化 到一定位置时,在动态的去变换样式,这样就达到了响应式布局的效果

好了,直接上代码:

// html 部分
<template>
  <div class="wrap">
    <!-- 这里 visible 解释下:主要是控制菜单栏的显示与隐藏-->
    <app-header class="app-header" :visible="visible"/>
    <!-- 这里 isCollapse 解释下:主要是 element UI 里的控制 侧边栏 缩放的
          使用动态样式 :class="adaptation.nav" 去改变布局
    -->
    <app-nav :class="adaptation.nav" :isCollapse="isCollapse" :direction="visible"/>
    <app-main :class="adaptation.main"/>
  </div>
</template>

<script>
// 引入三个主要 `积木` 
import AppHeader from './AppHeader'
import AppMain from './AppMain'
import AppNav from './AppNav'

export default {
  components: { AppHeader, AppMain, AppNav },
  created() {
    // 这里用了 箭头函数 其实可以不用 that 了,但是由于写 Es5 的习惯我就没改
    const that = this
    // 核心方法,主要 根据窗口的变化 来控制布局
    window.onresize = () => {
      window.screenWidth = document.body.clientWidth
      // 第二步
      that.screenWidth = window.screenWidth
      window.screenWidth >= 1200 ? that.isCollapse = false : that.isCollapse = true
      that.changeWidth(window.screenWidth)
    }
    window.onresize()
  },
  data() {
    return {
      adaptation: {
        nav: 'app-nav-lg',
        main: 'app-main-lg',
        class: ''
      },
      // 第一步
      screenWidth: document.body.clientWidth,
      visible: null,
      isCollapse: false
    }
  },
  methods: {
    // 第三步
    changeWidth(clientWidth) {
      this.visible = true
      // 主要根据 窗口变化 到一定位置时,变换样式
      if (clientWidth >= 1200) {
        // el-menu-vertical-demo el-menu-demo
        this.adaptation.nav = 'app-nav-lg'
        this.adaptation.main = 'app-main-lg'
      } else if (clientWidth >= 992) {
        this.adaptation.nav = 'app-nav-md'
        this.adaptation.main = 'app-main-md'
      } else if (clientWidth >= 768) {
        this.adaptation.nav = 'app-nav-sm'
        this.adaptation.main = 'app-main-sm'
      } else if (clientWidth < 768) {
        this.adaptation.nav = 'hidden-xs-only app-nav-xs'
        this.adaptation.main = 'app-main-xs'
        this.visible = false
      } else this.$message.warning({ message: '未知像素错误' })
      // console.log('当前窗口大小', clientWidth)
    }
  }
}
</script>

<style lang="scss" scoped>
  .wrap {
    height: 100%;
    overflow: hidden;

    .app-header {
      position: fixed;
      height: 60px;
      left: 0;
      top: 0;
      right: 0;
      z-index: 99;
      background: rgb(5, 32, 60);
    }

    .app-nav-lg, .app-nav-md, .app-nav-sm, .app-nav-xs {
      background: rgb(45, 56, 89);
      min-width: 60px;
      height: calc(100% - 0px);
      float: left;
      /*margin-top: 60px;*/
      overflow: hidden;
      user-select: none;
    }

    .app-nav-xs {
      width: 0;
      min-width: 0;
    }

    .app-main-lg::-webkit-scrollbar, .app-main-md::-webkit-scrollbar,
    .app-main-sm::-webkit-scrollbar, .app-main-xs::-webkit-scrollbar{
      display: none;
    }
    .app-main-lg, .app-main-md, .app-main-sm, .app-main-xs {
      padding: 80px 15px 0 15px;
      width: calc(100% - 230px);
      height: calc(100% - 0px);
      overflow: auto;
      scrollbar-width: none;
      float: right;
    }

    .app-main-md {
      width: calc(100% - 95px);
    }

    .app-main-sm {
      width: calc(100% - 95px);
    }

    .app-main-xs {
      width: calc(100% - 30px);
    }
  }
</style>

当然,这里不一定适合你的项目,前面我说了毕竟每个公司或个人的项目不同,最佳实践也会有所不同。只能说这是我的最初思路。但是这个还是有问题

存在一个函数被挂载在全局,只要窗口或者路由跳转发生 '风吹草动',就会执行 window.onresize 这个方法,所以像 AntD 里源码里的做法是放进 Redux 里去监听。Vue-ElementAdmin 是放在 Vuex 里去进行管理,这里就不做过多解释,因为涉及到的文件较多,解释起来很复杂,感兴趣的可以去看看源码

好了,今天的分享到此结束,感谢观看,如果觉得好,可以点个小赞支持一下。如果觉得哪里不明白,可以留言给我。放心,留言也不会回