这个Vue的Less代码中的@media样式要怎么样才能生效?

我写的这个Vue的Less样式为什么没有生效?

<template>
  <div class="grid-list">
    <slot />
  </div>
</template>
<script setup>
import {computed} from 'vue';

const props = defineProps({
  itemWidth: {
    type: String,
    default: '300px',
  },
});

const itemWidth = computed(() => {
  return props.itemWidth;
});
</script>
<style lang="less">
.grid-list {
  display: grid;
  gap: 16px;
  grid-auto-rows: minmax(172px, auto);
}

@iw: e(%('%d', v-bind(itemWidth)));

.loop(@index) when (@index < 20) {
  @media (min-width: calc(288px + 16px * (@index - 1) + @iw * @index)) {
    .grid-list {
      grid-template-columns: repeat(@index, 1fr);
    }
  }

  .loop(@index + 1);
}

.loop(1);
</style>

上面是我写的一个自定义组件,但是@media这里的代码没有生效,请问我这里少了什么步骤吗?

阅读 1.4k
avatarAI BotBETA

您提供的Vue组件代码使用了Less语言来编写样式,并试图通过Less的循环来生成一系列基于媒体查询的样式规则。然而,您的代码中存在几个问题,导致@media样式没有生效。

  1. Less不直接支持变量插值到calc函数中,这可能导致编译错误。
  2. Less的混合(mixins)和循环不直接支持动态创建媒体查询,因此您的方法可能不会按预期工作。

以下是您可以尝试的修改步骤,以便生成有效的媒体查询样式:

  1. 使用CSS变量:Vue 3支持在样式中使用CSS变量,这允许您根据组件的props动态地改变样式。不过,CSS变量不能直接用在媒体查询中,因此您可能需要使用JavaScript来计算媒体查询的值,并将它们添加到组件的class或style中。
  2. 避免在Less中使用循环创建媒体查询:Less的循环通常用于生成重复的CSS规则,而不是创建动态的媒体查询。媒体查询通常需要基于实际计算的断点来创建,而断点通常是由组件的props或其他动态因素决定的。
  3. 使用计算属性来动态设置样式:您可以通过Vue的计算属性来计算媒体查询的断点,并将它们以某种方式(例如,绑定到元素的class或style属性)应用到模板中。这通常意味着您需要编写一些JavaScript代码来管理这些样式,而不是完全依赖Less的预处理器功能。
  4. 使用第三方库:有些库可能提供了更高级的功能,可以帮助您根据props或其他因素动态生成媒体查询。这些库可能提供了更简洁的API来处理这类问题。

由于这个问题涉及到动态创建媒体查询,而Less并不直接支持这种用法,因此解决方案可能会比较复杂。您可能需要重新考虑如何组织您的代码,以便更好地利用Vue和CSS的功能来实现您的目标。

最后,请注意,对于动态媒体查询,通常更好的做法是在组件的JavaScript部分进行计算,并根据需要动态地添加或删除CSS类,而不是试图在样式预处理器中处理所有逻辑。

2 个回答
新手上路,请多包涵

把@media的样式代码放到下面,确保嵌套层级一样,就会覆盖上面的。

有点绕,但是大概能明白你期望在 less 中使用当前的 itemWith 变量的值来作为计算值。

但是你要明白 less 是预处理样式,在编译阶段就已经编译成了普通的CSS了,并不会获取到项目在浏览器中运行的值。除非你的 props.itemWith 是一个固定的值比如说:

<script setup>
const testStyle = {
  itemWidth: '300px'
}

</script>
<style lang="less">
.grid-list {
  display: grid;
  gap: 16px;
  grid-auto-rows: minmax(172px, auto);
}

@iw: e(%('%d', v-bind(testStyle.itemWidth)));

.loop(@index) when (@index < 20) {
  @media (min-width: calc(288px + 16px * (@index - 1) + @iw * @index)) {
    .grid-list {
      grid-template-columns: repeat(@index, 1fr);
    }
  }

  .loop(@index + 1);
}

.loop(1);
</style>

所以要达到你期望的目标,可以使用 CSS 自定义属性 来实现。举个例子

<template>
  <div  :style="cssVars">
    <div class="grid-list">
      <slot />
    </div>
  </div>
</template>
<script setup>
import {computed} from 'vue';

const props = defineProps({
  itemWidth: {
    type: String,
    default: '300px',
  },
});

const cssVars = computed(() => {
  return {
    "--itemWidth": props.itemWidth
  };
});
</script>
<style lang="less">
.grid-list {
  display: grid;
  gap: 16px;
  grid-auto-rows: minmax(172px, auto);
}

.loop(@index) when (@index < 20) {
  @media (min-width: calc(288px + 16px * (@index - 1) + var(--itemWidth) * @index)) {
    .grid-list {
      grid-template-columns: repeat(@index, 1fr);
    }
  }

  .loop(@index + 1);
}

.loop(1);
</style>

但是不一定对,我不太确定能否在 calc() 中使用 CSS variables

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题