Vue/Vuetify -基于组件尺寸的断点

sxpgvts3  于 2023-01-31  发布在  Vue.js
关注(0)|答案(3)|浏览(191)
    • bounty将在5天后过期**。回答此问题可获得+50的声誉奖励。specimen正在寻找来自声誉良好来源的答案

据我所知,Vuetify允许你基于***视口大小***定义断点。是否也可以基于***组件大小***定义断点?

  • 当概览页面上显示几个组件时,将使用更"紧凑"的布局,以便能够在大屏幕上并排显示组件。
  • 当仅示出一个组件时,它可能占用更多空间(在大屏幕上)。
  • 当在小屏幕上仅示出一个组件时,也可以使用"紧凑"布局。
  • 在小屏幕上,概览页面可以纵向而不是并排显示几个组成部分。

或者你能推荐一个更好的方法吗?

rvpgvaaj

rvpgvaaj1#

据我所知,Vuetify中没有这个功能,但是你可以隐藏包含该组件的v-col,其他列会占用释放出来的空间。

例如:https://codepen.io/olegnaumov/pen/rNpzvEX

hjzp0vay

hjzp0vay2#

由于不能依赖全局断点(至少对于基于组件数量的更改),因此可以向组件传递一个layout prop,该prop指示组件的内部布局。
Widget component

<template>
  <div>
    <div>Widget</div>
    <v-row :class="{ 'flex-column': layout === 'vertical' }">
      <v-col> Column 1 </v-col>
      <v-col> Column 2 </v-col>
      <v-col v-if="layout !== 'compact'"> Column 3 </v-col>
      <v-col v-if="layout !== 'compact'"> Column 4 </v-col>
    </v-row>
  </div>
</template>

<script>
export default {
  name: "Widget",
  props: {
    layout: {
      type: String,
      default: "normal", // Options: ['normal', 'vertical', 'compact']
    },
  },
};
</script>

然后,您可以使用Vuetify提供的两个指令来计算子组件和父容器的布局:v-mutate用于监视子级数量的变化(使用child修饰符),v-resize用于监视应用程序的大小调整。
Parent component

<template>
  <v-app v-resize="onResize">
    <v-container fluid>
      <v-row
        ref="widget_container"
        v-mutate.child="onMutate"
        :class="{ 'flex-column': layout_container === 'vertical' }"
      >
        <template v-for="n in show">
          <v-col :key="n">
            <widget :layout="layout_widget"></widget>
          </v-col>
        </template>
      </v-row>
    </v-container>
  </v-app>
</template>

<script>
import Widget from "/src/components/widget.vue";
export default {
  name: "App",
  components: {
    Widget,
  },
  data() {
    return {
      show: 2, // Any other method to change the number of widgets shown
               // See the codesanbox for one of them
      container_width: null,
      widget_width: null,
      // Tweak below values accordingly
      container_breackpoints: {
        400: "vertical", 
        900: "normal",
      },
      widget_breackpoints: {
        200: "compact",
        500: "normal",
      },
    };
  },
  computed: {
    layout_container() {
      let breackpoint = Object.keys(this.container_breackpoints)
        .sort((a, b) => b - a)
        .find((k) => this.container_width > k);
      return this.container_breackpoints[breackpoint] || "normal";
    },
    layout_widget() {
      if (this.layout_container === "vertical") return "vertical";
      let breackpoint = Object.keys(this.widget_breackpoints)
        .sort((a, b) => b - a)
        .find((k) => this.widget_width > k);
      return this.widget_breackpoints[breackpoint] || "normal";
    },
  },
  methods: {
    setLayout() {
      this.container_width = this.$refs.widget_container.clientWidth;
      this.widget_width =
        this.container_width / this.$refs.widget_container.children.length;
    },
    onMutate() {
      this.setLayout();
    },
    onResize() {
      this.setLayout();
    },
  },
};
</script>

请注意,这不是一个可用于生产的解决方案,而是一个概念验证,展示了v-mutatev-resize在此方面的用途。
您可以查看此Codesanbox进行演示。

ffscu2ro

ffscu2ro3#

您可以使用useResizeObserver并在元素上应用size类来编写自己的CSS规则,这些类又可以用来修改自身及其后代的CSS规则:
示例:

const { createApp, ref } = Vue;
const { createVuetify } = Vuetify;

const vuetify = createVuetify();
const { useResizeObserver } = VueUse;

const app = createApp({
  setup() {
    const el = ref(null)
    const size = ref('')
    useResizeObserver(el, (entries) => {
      const { width } = entries[0].contentRect;
      size.value =
        width < 600
          ? "xs"
          : width < 960
          ? "sm"
          : width < 1264
          ? "md"
          : width < 1904
          ? "lg"
          : "xl";
    });
    return { el, size };
  },
});
app.use(vuetify).mount("#app");
.xs span {
  color: orange;
}
.sm span {
  color: red;
}
.md span {
  color: blue;
}
.lg span {
  color: green;
}
<script src="https://cdn.jsdelivr.net/npm/vue@3.2.45/dist/vue.global.prod.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify@3.1.1/dist/vuetify.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/vuetify@3.1.1/dist/vuetify.min.css" rel="stylesheet"/>
<script src="https://unpkg.com/@vueuse/shared"></script>
<script src="https://unpkg.com/@vueuse/core"></script>

<div id="app">
  <v-app>
    <v-main class="h-100">
      <v-row no-gutters class="h-100" style="background: #f5f5f5">
        <v-col
          class="h-100"
          cols="12"
          sm="6"
          lg="9"
        >
          <v-card class="h-100 pa-2" :class="size" ref="el">
            v-card: {{ size }} <br>
            window: 
            <span class="d-inline-block d-sm-none">xs</span>
            <span class="d-none d-sm-inline-block d-md-none">sm</span>
            <span class="d-none d-md-inline-block d-lg-none">md</span>
            <span class="d-none d-lg-inline-block d-xl-none">lg</span>
            <span class="d-none d-xl-inline-block">xl</span>
          </v-card>
        </v-col>
      </v-row>
    </v-main>
  </v-app>
</div>

相关问题