显示移动浏览器的不同Vuejs组件

sea*_*717 14 vue.js vuejs2

我正在使用Vue 2.0开发SPA.到目前为止开发的组件适用于"桌面"浏览器,例如,我有

Main.vue,ProductList.vue,ProductDetail.vue,

我想要移动浏览器的另一组组件,例如MainMobile.vue,ProductListMobile.vue,ProductDetailMobile.vue,

我的问题是,在移动浏览器中查看时,在何处以及如何使我的SPA呈现移动版组件?

请注意,我明确希望避免让我的组件响应.我想保留它们的两个单独版本.

谢谢,

Zha*_*rik 22

我有一个简单的Vue.js解决方案:

<div v-if="!isMobile()">
  <desktop>
  </desktop>
</div>
<div v-else>
  <mobile>
  </mobile>
</div>
Run Code Online (Sandbox Code Playgroud)

和方法:

methods: {
 isMobile() {
   if(/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
     return true
   } else {
     return false
   }
 }
}
Run Code Online (Sandbox Code Playgroud)

  • 很好,但使用 `return ...` 而不是 `if (...) { return true } else { return false }` (10认同)
  • iPhone之后出现语法错误(|而不是||) (7认同)
  • 我一直在做一些研究,显然使用用户代理嗅探来检测移动设备并不是一个好主意。我建议您参考以下文档 https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent,您可以在其中查找“移动设备检测”部分。它向您展示了如何通过检查移动设备是否具有触摸屏来检测移动设备,仅将用户代理嗅探作为最后的手段。希望有帮助。 (5认同)
  • 它不会拿起触摸屏设备的笔记本电脑吗?我觉得这会是一个问题 (3认同)

Moh*_*_PH 18

我有一个想法,使用mixin检测浏览器移动或桌面(此答案中的 js代码示例)..然后使用v-if,例如

<production-list v-if="!isMobile()"></production-list>
<production-list-mobile v-else></production-list-mobile>
Run Code Online (Sandbox Code Playgroud)

所以这是一个关于https://jsfiddle.net/Ldku0xec/的例子

  • 您还可以使用命名视图并在 &lt;router-view&gt; 实例上应用 isMobile 逻辑,以避免在每个组件上重复此逻辑。 (2认同)

Chi*_*dra 7

我正在为此寻找解决方案并来到这里,但我找不到我需要的东西:

  1. 异步导入以仅将基于视口所需的内容加载到包中。
  2. 如果调整布局大小,则能够提供不同的布局

我混合并匹配了我在网上阅读的一些内容,包括这里的答案,所以我想我会回来并将我所有的知识整合到一个功能中,供其他人查看:

/**
 * Breakpoint configuration to be in line with element-ui's standards
 * @type {{LABELS: string[], VALUES: number[]}}
 */
const BREAKPOINTS = {
    LABELS: ['xs', 'sm', 'md', 'lg', 'xl'],
    VALUES: [0, 768, 992, 1200, 1920, Infinity]
};


/**
 * @typedef ViewFactory
 * @type function
 * A function which returns a promise which resolves to a view. Used to dynamically fetch a view file on the fly during
 * run time on a need basis
 */


/**
 * A helper to get a responsive route factory which renders different views based on the current view point
 * @param {{xs:[ViewFactory],sm:[ViewFactory],md:[ViewFactory],lg:[ViewFactory]}} map - A map of breakpoint key to a ViewFactory
 * @returns {ViewFactory} - A view factory which invokes and returns an item supplied in the map based on the current viewport size
 */
export default function responsiveRoute(map) {
    return function getResponsiveView() {
        const screenWidth = document.documentElement.clientWidth;

        // Find the matching index for the current screen width
        const matchIndex = BREAKPOINTS.VALUES.findIndex((item, idx) => {
            if (idx === 0) {
                return false;
            }
            return screenWidth >= BREAKPOINTS.VALUES[idx - 1] && screenWidth < BREAKPOINTS.VALUES[idx];
        }) - 1;


        if (map[BREAKPOINTS.LABELS[matchIndex]]) {
            // Perfect match, use it
            return map[BREAKPOINTS.LABELS[matchIndex]]();
        } else {
            // Go down the responsive break points list until a match is found
            let counter = matchIndex;
            while (counter-- > 0) {
                if (map[BREAKPOINTS.LABELS[counter]]) {
                    return map[BREAKPOINTS.LABELS[counter]]();
                }
            }
            return Promise.reject({
                code: 500,
                info: 'No component matched the breakpoint - probably a configuration error'
            });
        }
    };
} 
Run Code Online (Sandbox Code Playgroud)

用法:

const router = new Router({
    mode: 'history',
    base: process.env.BASE_URL,
    routes:[{
      path: '/login',
      name: 'login',
      component: responsiveRoute({
          // route level code-splitting
          // this generates a separate chunk (login-xs.[hash].js) for this route
          // which is lazy-loaded when the route is visited.
          xs: () => import(/* webpackChunkName: "login-xs" */ './views/Login/Login-xs.vue'),
          // sm key is missing, it falls back to xs
          md: () => import(/* webpackChunkName: "login-md" */ './views/Login/Login-md.vue')
          // lg, xl keys are missing falls back to md
      }) 
  }]
}); 
Run Code Online (Sandbox Code Playgroud)

这个怎么运作:

Vue Router 支持将component键定义为一个函数,该函数返回支持异步路由的承诺。最常见的方法是使用import()返回承诺的 webpack函数。返回承诺的函数仅在路由即将呈现时调用,以确保我们可以延迟加载我们的组件

responsiveRoute函数接受这些函数的映射,键为不同的断点设置,并返回一个函数,该函数在调用时检查可用的视口大小并返回调用正确的承诺工厂并返回它返回的承诺。

笔记:

我喜欢这种方法,因为它不需要应用程序架构或路由配置以某种方式。使用开箱即用的 Vue Router 功能,它非常即插即用。它也不强制您为每个断点-路由组合定义一个视图。您可以像往常一样定义一条路线,而没有这个(延迟加载或不加载),沿着其他使用它的路线没有任何问题。

此方法不使用用户代理嗅探,而是使用 的可用宽度document.documentElement。我看到了其他推荐的方法,例如window.screen.width无论窗口大小如何,都可以提供确切的设备屏幕大小或更健壮的window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth. 根据需要混合搭配。

我的断点是(数字和它们的值)基于 element-ui 断点,因为我将其用于正常的响应式设计。这可以通过更改顶部的常量再次根据需要进行配置


Bea*_*eve 7

这有点晚了,但是,如果你们中的任何人想要绑定视口大小的观察者,和/或在页面加载时检查。它需要编写很多样板,但对小型应用程序很有用。

export default {
  data: () => ({
    isMobile: false
  }),

  beforeDestroy () {
    if (typeof window !== 'undefined') {
      window.removeEventListener('resize', this.onResize, { passive: true })
    }
  },

  mounted () {
    this.onResize()
    window.addEventListener('resize', this.onResize, { passive: true })
  },

  methods: {
    onResize () {
      this.isMobile = window.innerWidth < 600
    }
  }
}
Run Code Online (Sandbox Code Playgroud)


Der*_*rzu 6

我遇到了同样的问题,我使用一个中性的,没有布局的vue文件(Init.vue)解决了该问题,该文件将通过移动设备和台式机访问,并且该文件重定向到正确的文件。

假设我有Main.vue和MainMobile.vue。我将添加一个将重定向的Init.vue。所以我的router / index.js是:

import Router from 'vue-router'
import Vue from 'vue'
import Main from '@/components/Main'
import MainMobile from '@/components/MainMobile'
import Init from '@/components/Init'

Vue.use(Router)

export default new Router({
  routes: [
     {
        path: '/',
        name: 'Root',
        component: Init
     },
    {
      path: '/Main',
      name: 'Main',
      component: Main
    },
    {
      path: '/MainMobile',
      name: 'MainMobile',
      component: MainMobile
    },
  ]
})
Run Code Online (Sandbox Code Playgroud)

在Init.vue文件中,将进行移动/桌面检测:

<template>
</template>
<script>
    export default {
        name: 'Init',
        methods: {
            isMobile() {
                if( screen.width <= 760 ) {
                    return true;
                }
                else {
                    return false;
                }
            }
        },
        created() {
            if (this.isMobile()) {
                this.$router.push('/MainMobile');
            }
            else {
                this.$router.push('/Main');
            }
        }
    }
</script>
<style scoped>
</style>
Run Code Online (Sandbox Code Playgroud)

使用的isMobile()函数非常简单,您可以更改为其他任何函数。

  • 在我看来最好的解决方案。通过这种方式,您可以使用真实的屏幕尺寸,这比检查用户代理/设备/任何东西更安全、更有效。 (2认同)

syl*_*loc 6

对于 vuetify 用户,您可以使用带有动态组件加载的断点。假设您有两个组件;DesktopLayout.vue 和 MobileLayout.vue。在要加载不同布局的页面中,定义一个这样的动态组件;

<component :is="currentComponent"></component>
Run Code Online (Sandbox Code Playgroud)

添加一个名为“currentComponent”的计算属性。

computed: {
    currentComponent() {
        return this.$vuetify.breakpoint.xsOnly
            ? "MobileLayout"
            : "DesktopLayout";
    }
}
Run Code Online (Sandbox Code Playgroud)

this.$vuetify.breakpoint.xsOnly将仅在超小屏幕上使用“MobileLayout”。vuetify 中定义了很多断点。例如,您可以使用“mdAndDown”为中等尺寸和向下的屏幕选择一个范围。


Esc*_*ape 5

Beaudinn Greves 答案的扩展版本:

  • 使用命名路由器视图
  • 监听窗口调整大小,如果宽度小于 xy,则设置 isMobile true
  • 在 router.js 中使用“组件”而不是“组件”并导入(您可以使用 require)桌面和移动组件

应用程序.vue:

<template>
  <div id="app" class="container grid-lg">
    <router-view v-if="!store.app.isMobile"/>
    <router-view v-else name="mobile"/>
  </div>
</template>
...
name: "app",
  data: function() {
  return {
    store: this.$store.state
  };
},
mounted () {
  this.onResize()
  window.addEventListener('resize', this.onResize, { passive: true })
},
methods: {
  onResize () {
    this.store.app.isMobile = window.innerWidth < 600
  }
},
beforeDestroy () {
  if (typeof window !== 'undefined') {
    window.removeEventListener('resize', this.onResize, { passive: true })
  }
}
Run Code Online (Sandbox Code Playgroud)

路由器.js:

routes: [
  {
    path: '/',
    name: 'home',
    components: {
      default: Home,
      mobile: HomeMobile
    }
  }
]
Run Code Online (Sandbox Code Playgroud)