flexible.client.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. // plugins/smart-flexible.client.js
  2. class ResponsiveAdapter {
  3. constructor() {
  4. this.isMobile = this.checkMobile()
  5. this.init()
  6. }
  7. checkMobile() {
  8. const ua = navigator.userAgent.toLowerCase()
  9. const mobileKeywords = [
  10. 'iphone', 'ipod', 'android.*mobile',
  11. 'windows.*phone', 'blackberry.*mobile',
  12. 'mobile', 'tablet'
  13. ]
  14. const isMobileUA = mobileKeywords.some(keyword =>
  15. new RegExp(keyword).test(ua)
  16. )
  17. const screenWidth = window.innerWidth
  18. const isSmallScreen = screenWidth <= 768
  19. return isMobileUA || isSmallScreen
  20. }
  21. init() {
  22. const docEl = document.documentElement
  23. if (this.isMobile) {
  24. // 移动端逻辑
  25. this.initMobile(docEl)
  26. } else {
  27. // PC 端逻辑
  28. this.initPC(docEl)
  29. }
  30. // 添加设备标识类
  31. this.addDeviceClass(docEl)
  32. // 监听窗口变化
  33. window.addEventListener('resize', () => {
  34. this.handleResize(docEl)
  35. })
  36. }
  37. initMobile(docEl) {
  38. const dpr = window.devicePixelRatio || 1
  39. // 设置 viewport meta
  40. this.setViewport(dpr)
  41. // 设置 rem
  42. const setRem = () => {
  43. const rem = docEl.clientWidth / 10
  44. docEl.style.fontSize = rem + 'px'
  45. }
  46. setRem()
  47. window.addEventListener('resize', setRem)
  48. // 存储方法供外部调用
  49. this.setRem = setRem
  50. }
  51. initPC(docEl) {
  52. // PC 端使用响应式 rem
  53. const setPCRem = () => {
  54. const width = docEl.clientWidth
  55. // 响应式断点
  56. let fontSize
  57. if (width >= 1920) {
  58. fontSize = 192 // 1920/10
  59. } else if (width >= 1600) {
  60. fontSize = 160 // 1600/10
  61. } else if (width >= 1440) {
  62. fontSize = 144 // 1440/10
  63. } else if (width >= 1366) {
  64. fontSize = 136.6 // 1366/10
  65. } else if (width >= 1200) {
  66. fontSize = 120 // 1200/10
  67. } else {
  68. fontSize = 100 // 小于1200时的基准
  69. }
  70. docEl.style.fontSize = fontSize + 'px'
  71. }
  72. setPCRem()
  73. window.addEventListener('resize', setPCRem)
  74. this.setPCRem = setPCRem
  75. }
  76. setViewport(dpr) {
  77. let viewport = document.querySelector('meta[name="viewport"]')
  78. if (!viewport) {
  79. viewport = document.createElement('meta')
  80. viewport.name = 'viewport'
  81. document.head.appendChild(viewport)
  82. }
  83. if (this.isMobile) {
  84. viewport.content = `width=device-width, initial-scale=${1/dpr}, maximum-scale=${1/dpr}, minimum-scale=${1/dpr}, user-scalable=no`
  85. } else {
  86. viewport.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no'
  87. }
  88. }
  89. addDeviceClass(docEl) {
  90. docEl.classList.remove('is-pc', 'is-mobile')
  91. docEl.classList.add(this.isMobile ? 'is-mobile' : 'is-pc')
  92. }
  93. handleResize(docEl) {
  94. const wasMobile = this.isMobile
  95. this.isMobile = this.checkMobile()
  96. if (wasMobile !== this.isMobile) {
  97. // 设备类型发生变化
  98. this.addDeviceClass(docEl)
  99. if (this.isMobile) {
  100. this.initMobile(docEl)
  101. } else {
  102. this.initPC(docEl)
  103. }
  104. } else {
  105. // 同设备类型,只更新 rem
  106. if (this.isMobile && this.setRem) {
  107. this.setRem()
  108. } else if (!this.isMobile && this.setPCRem) {
  109. this.setPCRem()
  110. }
  111. }
  112. }
  113. }
  114. // 初始化
  115. export default defineNuxtPlugin(() => {
  116. if (process.client) {
  117. new ResponsiveAdapter()
  118. }
  119. })