vue如何实现pc和移动端布局详细代码

 更新时间:2023年10月11日 10:01:02   作者:我是沐辰  
这篇文章主要给大家介绍了关于vue如何实现pc和移动端布局的相关资料, Vue响应式布局适配是一种根据设备特性自动调整布局的方法,文中通过代码以及图文介绍的非常详细,需要的朋友可以参考下

1.核心点

  • 本方案未采用同一套代码去响应各端的方式去开发,个人觉得兼容太麻烦、样式难以精确控制,遂采用 pc 和 移动端 两套代码、一套路由规则的方式去开发
  • 本方案适用于官网类、展示类的项目
  • 本方案在移动端中使用 vw 作为基本单位,使用 postcss-px-to-viewport 实现移动端 px 单位自动转为 vw

2.开撸

2.1 获取当前设备类型,共享给全局使用

  • vuex 中定义名为 device 的 state,用于全局共享当前设备(pc || 移动)
export default new Vuex.Store({
  state: {
    device: 'pc'
  },
  mutations: {
    setDevice (state, data) {
      state.device = data
    }
  }
})
  • App.vue 中使用像素来检测当前所处设备
<template>
  <div id="app">
    <router-view />
  </div>
</template>
<script>
import { mapMutations } from 'vuex'
import { throttle } from 'lodash-es'
export default {
  created () {
    // resize节流
    this.resizeChange = throttle(this.resizeChange, 200)
    this.resizeChange()
    window.addEventListener('resize', this.resizeChange, false)
  },
  methods: {
    ...mapMutations(['setDevice']),
    resizeChange () {
      // 判断是否是 pc 或者 移动端,也可以用机型之类的条件来判断,个人觉得用像素更简单快捷
      // 默认设置当屏幕宽度 > 1000 时,为PC端
      if (document.documentElement.clientWidth > 1000) {
        this.setDevice('pc')
      } else {
        // 默认设置当屏幕宽度 <= 1000 时,为移动端
        this.setDevice('m')
      }
    }
  },
  destroyed () {
    window.removeEventListener('resize', this.resizeChange, false)
  }
}
</script>

到目前为止,我们可以通过 vuex 中的 device 拿到当前的设备类型,pc 对应的是 pc 端,m 对应的是移动端

2.2 页面文件结构及关键代码

  • 页面文件结构

  • 代码
// index.vue
<template>
  <div class="index">
    <component :is="$store.state.device"></component>
  </div>
</template>
<script>
import m from './device/m.vue'
import pc from './device/pc.vue'
export default {
  name: 'index',
  components: {
    pc,
    m
  }
}
</script>
// device 目录下的 m.vue 或 pc.vue
// m.vue
<template>
  <div class="index-m">
  	<p> 这里没有其他特殊之处,正常写 移动端 和 pc 端代码即可 </p>
  	<p> m.vue 和 pc.vue 没有本质差异,仅修改 类名 或 组件名称后缀为 -pc </p>
  </div>
</template>
<script>
export default {
  name: 'index-m'
}
</script>
<style lang="scss" scoped>
.index-m {
	// 如果是 m.vue,这里正常使用 px 作为基本单位
}
</style>

在首页 index.vue 中,将其所对应的 pc 端代码定义为 pc.vue,对应的 移动端 代码定义为 m.vue,并导入到 index.vue 中,分别命名为 pc 和 m,而后使用动态组件,并使用$store.state.device来控制当前所展示的页面为 pc端 还是 移动端。

2.3 使用 postcss-px-to-viewport 将项目中的 px 单位转换为 vw

截止到目前,我们已经实现了不同设备下(pc端 或 移动端)代码的按需展示,但是有一个问题亟待解决。

众所周知,移动端设备的屏幕大小不一、“千奇百怪”,如果继续使用 px 作为基本单位,最后呈现的效果必然不理想,经过对比,决定使用 vw 来作为移动端的基本单位。

但是我们都知道,一般情况下设计稿的尺寸是固定的 px 单位,在开发时需要将 px 单位转为 vw 来进行开发,但是这一过程略显繁琐,哪怕安装了 vs code 的单位转换插件依旧差强人意,这时,我们便可以请出 postcss-px-to-viewport 来帮我们解决这一问题。

  • 作用
    该插件可以让我们在写 css 代码的时候正常的使用 px,其会将 px 单位自动转换为视口单位 (vw, vh, vmin, vmax)

  • 文档

  • 安装

npm install postcss-px-to-viewport --save-dev
yarn add -D postcss-px-to-viewport
  • 配置
// .postcssrc.js
module.exports = {
  plugins: {
      // 用来给不同的浏览器自动添加相应前缀,如-webkit-,-moz-等等
      autoprefixer: {}, 
      "postcss-px-to-viewport": {
        // 需要转换的单位,默认为"px"
        unitToConvert: 'px',
        viewportWidth: 375,
        // 单位转换后保留的精度
        unitPrecision: 3,
        // 能转化为vw的属性列表
        propList: [
          '*'
        ],
        // 希望使用的视口单位
        viewportUnit: 'vw',
        // 字体使用的视口单位
        fontViewportUnit: 'vw',
        // 设置最小的转换数值,如果为1的话,只有大于1的值会被转换
        minPixelValue: 1,
        // 仅转换的文件,这里不要使用 \/ 去匹配文件,不生效??
        // 这里还有一个坑,就是如果使用了 include 规则的话,正常的版本不生效,可以安装这个
        // "postcss-px-to-viewport": "github:evrone/postcss-px-to-viewport"
        include: [/device\\m.vue/]
      }
  }
};

配置include: [/device\\m.vue/]使我们移动端代码中的 px 单位自动转换为 vw,而 pc 端的代码不受影响。

2.4 使用 node 自动创建符合需求的页面

2.4.1 创建脚本文件

  • 根目录下创建 scripts 及其子文件

  • template.js
module.exports = {
  viewTemplate: viewName => {
    return `
<template>
  <div class="${viewName}">
    <component :is="$store.state.device"></component>
  </div>
</template>
<script>
import m from './device/m.vue'
import pc from './device/pc.vue'
export default {
  name: '${viewName}',
  components: {
    pc,
    m
  }
}
</script>
`
  },
// 移动端 页面基本结构
  mTemplate: viewName => {
    return `
<template>
  <div class="${viewName}-m">
  </div>
</template>
<script>
export default {
  name: '${viewName}-m'
}
</script>
<style lang="scss" scoped>
.${viewName}-m {
}
</style>
`
  },
// pc端 页面基本结构
  pcTemplate: viewName => {
    return `
<template>
  <div class="${viewName}-pc">
  </div>
</template>
<script>
export default {
  name: '${viewName}-pc'
}
</script>
<style lang="scss" scoped>
.${viewName}-pc {
}
</style>
`
  }
}
  • generateView.js
// generateView.js
const chalk = require('chalk')
const path = require('path')
const fs = require('fs')
const log = message => console.log(chalk.green(`${message}`))
const successLog = message => console.log(chalk.blue(`${message}`))
const errorLog = error => console.log(chalk.red(`${error}`))
const { viewTemplate, mTemplate, pcTemplate } = require('./template')
const generateFile = (path, data) => {
  if (fs.existsSync(path)) {
    errorLog(`${path}文件已存在`)
    return
  }
  return new Promise((resolve, reject) => {
    fs.writeFile(path, data, 'utf8', err => {
      if (err) {
        errorLog(err.message)
        reject(err)
      } else {
        resolve(true)
      }
    })
  })
}
// 创建页面目录
const dotExistDirectoryCreate = (directory) => {
  return new Promise((resolve) => {
    mkdirs(directory, function () {
      resolve(true)
    })
  })
}
// 递归创建目录
const mkdirs = (directory, callback) => {
  var exists = fs.existsSync(directory)
  if (exists) {
    callback()
  } else {
    mkdirs(path.dirname(directory), function () {
      fs.mkdirSync(directory)
      callback()
    })
  }
}
// 获取页面名称
const getViewName = (viewPath) => {
  const arr = viewPath.split('\\')
  return arr[arr.length - 1]
}
log('请输入要生成的页面组件名称(无需添加.vue后缀)、支持深层目录解析(dirName/viewName)、页面将生成在 views/目录下')
let viewName = ''
process.stdin.on('data', async chunk => {
  const inputName = String(chunk).trim().toString()
  // Vue页面组件路径
  let viewPath = path.resolve(__dirname, '../src/views', inputName)
  viewName = getViewName(inputName)
  viewPath = path.resolve(viewPath, viewName + '.vue')
  const viewDirectory = path.dirname(viewPath)
  // 检查界面是否存在
  const hasViewExists = fs.existsSync(viewPath)
  if (hasViewExists) {
    errorLog(`${inputName}页面已存在,请重新输入`)
    return
  }
  try {
    // 1.生成页面目录
    log(`正在生成页面目录 ${viewDirectory}`)
    await dotExistDirectoryCreate(viewDirectory)
    // 2.生成页面子目录
    const sonViewDirectory = path.resolve(viewDirectory, './device')
    log(`正在生成页面子目录 ${sonViewDirectory}`)
    await dotExistDirectoryCreate(sonViewDirectory)
    // 3.生成 m.vue 页面
    const mViewPath = path.resolve(sonViewDirectory, './m.vue')
    log(`正在生成子目录子页面文件 ${mViewPath}`)
    await generateFile(mViewPath, mTemplate(viewName))
    // 4.生成 pc.vue 页面
    const pcViewPath = path.resolve(sonViewDirectory, './pc.vue')
    log(`正在生成子目录子页面文件 ${pcViewPath}`)
    await generateFile(pcViewPath, pcTemplate(viewName))
    // 5.生成页面
    log(`正在生成页面文件 ${viewPath}`)
    await generateFile(viewPath, viewTemplate(viewName))
    successLog('生成成功')
  } catch (e) {
    errorLog(e.message)
  }
  process.stdin.emit('end')
})
process.stdin.on('end', () => {
  log('exit')
  process.exit()
})
  • package.json 中 scripts 节点下添加如下代码
  "new:view": "node ./scripts/generateView"

2.4.2 使用脚本生成符合需求的页面

  • 打开终端,输入 npm run new:view
  • 根据提示,输入要生成的文件名称(支持深层目录解析)
  • 下图中我们创建了一个名为 about 的页面,可以看到,只需要一个指令及文件名,我们便得到了想要的页面结构,极大的提高了开发效率

3.持续优化

经过实践发现,pc端 和 移动端 的差别更多体现在页面元素的大小、位置、显隐上,而实际的业务逻辑变化并不大,上述方案中并未抽离页面的 js 代码,导致代码存在冗余,这里我们可以使用 mixins 来优化。

举例来讲,我们可以在首页 index 页面目录下添加一个 mixin.js 文件,将 device/pc.vue 和 device/m.vue 的公共业务逻辑抽离到该文件中,从而实现复用。

因项目较小,我也是后知后觉的才想到可以进一步优化,现如今项目已部署,因此就没有再调整,可以按照上述方案自行优化调整。

到此这篇关于vue如何实现pc和移动端布局的文章就介绍到这了,更多相关vue pc和移动端布局内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • vue中正确使用jsx语法的姿势分享

    vue中正确使用jsx语法的姿势分享

    这篇文章主要给大家介绍了关于vue中正确使用jsx的相关资料,JSX就是Javascript和XML结合的一种格式,React发明了JSX,利用HTML语法来创建虚拟DOM,当遇到<,JSX就当HTML解析,遇到{就当JavaScript解析,需要的朋友可以参考下
    2021-07-07
  • vue中v-model如何绑定多循环表达式实战案例

    vue中v-model如何绑定多循环表达式实战案例

    v-model绑定的变量无论是对象还是数组都是绑定的value值,下面这篇文章主要给大家介绍了关于vue中v-model如何绑定多循环表达式的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-11-11
  • vue.js diff算法原理详细解析

    vue.js diff算法原理详细解析

    这篇文章主要介绍了vue.js diff算法原理详细解析,diff算法可以看作是一种对比算法,对比的对象是新旧虚拟Dom。顾名思义,diff算法可以找到新旧虚拟Dom之间的差异,但diff算法中其实并不是只有对比虚拟Dom,还有根据对比后的结果更新真实Dom
    2022-06-06
  • Vue中Table组件行内右键菜单实现方法(基于 vue + AntDesign)

    Vue中Table组件行内右键菜单实现方法(基于 vue + AntDesign)

    这篇文章主要介绍了Vue中Table组件行内右键菜单实现方法,该项目是基于 vue + AntDesign的,具体实例代码给大家介绍的非常详细 ,需要的朋友可以参考下
    2019-11-11
  • vue-cli3配置与跨域处理方法

    vue-cli3配置与跨域处理方法

    这篇文章主要介绍了vue-cli3配置与跨域处理方法,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-08-08
  • Vue 实现v-for循环的时候更改 class的样式名称

    Vue 实现v-for循环的时候更改 class的样式名称

    这篇文章主要介绍了Vue 实现v-for循环的时候更改 class的样式名称,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-07-07
  • 解决Vue打包上线之后部分CSS不生效的问题

    解决Vue打包上线之后部分CSS不生效的问题

    今天小编就为大家分享一篇解决Vue打包上线之后部分CSS不生效的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-11-11
  • Vue进阶之利用transition标签实现页面跳转动画

    Vue进阶之利用transition标签实现页面跳转动画

    这篇文章主要为大家详细介绍了Vue如何利用transition标签实现页面跳转动画,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起一下
    2023-08-08
  • 安装多版本Vue-CLI的实现方法

    安装多版本Vue-CLI的实现方法

    这篇文章主要介绍了安装多版本Vue-CLI的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • Vue基础教程之条件渲染和列表渲染

    Vue基础教程之条件渲染和列表渲染

    Vue会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做会使Vue变得非常快,下面这篇文章主要给大家介绍了Vue基础教程之条件渲染和列表渲染的相关资料,需要的朋友可以参考下
    2021-11-11

最新评论