我正在一个nuxt.js项目中,我需要确定computed
属性内的样式,并基于div
应用于screen size
,如下面的示例所示:
基本示例
<template>
<div :style="css"></div>
</template>
<script>
export default {
computed: {
css () {
let width = window.innerWidth
// ... mobile { ... styles }
// ... desktop { ... styles }
// ... if width is less than 700, return mobile
// ... if width greater than 700, return desktop
}
}
}
</script>
真实示例
<template>
<div :style="css">
<slot />
</div>
</template>
<script>
export default {
props: {
columns: String,
rows: String,
areas: String,
gap: String,
columnGap: String,
rowGap: String,
horizontalAlign: String,
verticalAlign: String,
small: Object,
medium: Object,
large: Object
},
computed: {
css () {
let small, medium, large, infinty
large = this.generateGridStyles(this.large)
medium = this.generateGridStyles(this.medium)
small = this.generateGridStyles(this.small)
infinty = this.generateGridStyles()
if (this.mq() === 'small' && this.small) return Object.assign(infinty, small)
if (this.mq() === 'medium' && this.medium) return Object.assign(infinty, medium)
if (this.mq() === 'large' && this.large) return Object.assign(infinty, large)
if (this.mq() === 'infinty') return infinty
}
},
methods: {
generateGridStyles (options) {
return {
'grid-template-columns': (options !== undefined) ? options.columns : this.columns,
'grid-template-rows': (options !== undefined) ? options.rows : this.rows,
'grid-template-areas': (options !== undefined) ? options.areas : this.areas,
'grid-gap': (options !== undefined) ? options.gap : this.gap,
'grid-column-gap': (options !== undefined) ? options.columnGap : this.columnGap,
'grid-row-gap': (options !== undefined) ? options.rowGap : this.rowGap,
'vertical-align': (options !== undefined) ? options.verticalAlign : this.verticalAlign,
'horizontal-align': (options !== undefined) ? options.horizontalAlign : this.horizontalAlign,
}
},
mq () {
let width = window.innerWidth
if (width < 600) return 'small'
if (width > 600 && width < 992) return 'medium'
if (width > 992 && width < 1200) return 'large'
if (width > 1200) return 'infinty'
}
}
}
</script>
<style lang="scss" scoped>
div {
display: grid;
}
</style>
利用pages.vue上的GridLayout
组件
<template>
<GridLayout
columns="1fr 1fr 1fr 1fr"
rows="auto"
gap="10px"
verital-align="center"
:small="{
columns: '1fr',
rows: 'auto auto auto auto',
}"
>
<h1>1</h1>
<h1>2</h1>
<h1>3</h1>
<h1>3</h1>
</GridLayout>
</template>
<script>
import { GridLayout } from '@/components/bosons'
export default {
layout: 'blank',
components: {
GridLayout
},
}
</script>
<style lang="scss" scoped>
h1 {
background: #000;
color: #fff;
}
</style>
不起作用,它在
windows is note defined
中产生错误if (this.mq() === 'small')
这在pure Vue.js
上可以很好地工作,但是我知道它在Nuxt.js上不起作用,因为它是服务器端渲染,很有意义,但是我如何使它工作呢?
我最接近的是将样式代码移至mounted
方法中或将样式代码包装在if (process.client) {...}
中,但是任何其他选择都会生成特定的delay
,{{1 }},例如:
process.client vs without the process.client
jump / delay on the layout when uses process.client condition
我该如何立即使它工作?在安装Vue.js的默认行为之前,我如何拥有屏幕宽度?
答案 0 :(得分:0)
这是一个古老的问题,由于服务器渲染而发生,如下面的github问题所述。
.vue文件
<script>
if (process.browser) {
require('aframe')
}
export default {
}
</script>
nuxt.config.js
build: {
vendor: ['aframe']
}
参考:
https://github.com/nuxt/nuxt.js/issues/30#issuecomment-264348589
https://nuxtjs.org/faq/window-document-undefined/
答案 1 :(得分:0)
我怀疑这是因为Nuxt框架正在尝试在没有窗口对象的服务器端进行计算。您需要检查process.client
,以确保它在浏览器中进行了计算:
export default {
computed: {
css () {
if (process.client) {
let width = window.innerWidth
// ... mobile { ... styles }
// ... desktop { ... styles }
// ... if width is less than 700, return mobile
// ... if width greater than 700, return desktop
} else {
return { /*empty style object*/ }
}
}
}
}
关于延迟,它有点“ hacky”,但是如果window
不可用,则可以返回null,并在计算出的属性可用后立即显示。您仍然需要等待一段时间才能看到它,因为问题的根源在于该样式将在下一次DOM更新中应用。
<template>
<div :style="css" v-show="css">
</div>
</template>
<script>
export default {
computed: {
css () {
if (process.client) {
let width = window.innerWidth
// ... mobile { ... styles }
// ... desktop { ... styles }
// ... if width is less than 700, return mobile
// ... if width greater than 700, return desktop
} else {
return null
}
}
}
}
</script>
或者,在下一次DOM更新中应用css时,您可以将data属性与Vue。$ nextTick()一起使用(但本质上是相同的):
<template>
<div :style="css" v-show="reveal">
</div>
</template>
<script>
export default {
data() {
return {
reveal: false
}
},
computed: {
css () {
if (process.client) {
let width = window.innerWidth
// ... mobile { ... styles }
// ... desktop { ... styles }
// ... if width is less than 700, return mobile
// ... if width greater than 700, return desktop
} else {
return { /*empty style object*/ }
}
}
},
mounted() {
this.$nextTick(() => {
this.reveal = true
});
}
}
</script>
但是,从您的问题来看,您似乎想应用自适应布局。最好的方法是将scope
放入您的style
标记中并使用CSS断点。这样可以解决延迟问题,并使样式和逻辑脱钩。
<template>
<div class="my-responsive-component">
</div>
</template>
<script>
export default {
computed: { /* nothing to see here! */ }
}
</script>
<style lang="css" scoped>
.my-responsive-component {
height: 100px;
width: 100px;
}
@media only screen and (max-width: 700px) {
.my-responsive-component { background: yellow; }
}
@media only screen and (min-width: 700px) {
.my-responsive-component { background: cyan; }
}
</style>
顺便说一句,顺便说一句,对于计算属性,请完全使用正确的if / else语句。使用if (!process.client) return { /* empty style object */}
之类的东西有时会在Vue计算的属性中产生一些意外的行为。