Yun*_*lva 5 javascript vue.js vuejs2 nuxt.js
我正在开发一个 nuxt.js 项目,我需要确定属性中的样式computed并应用于divbased on 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>
Run Code Online (Sandbox Code Playgroud)
真实的例子
<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>
Run Code Online (Sandbox Code Playgroud)
使用GridLayoutpages.vue上的组件
<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>
Run Code Online (Sandbox Code Playgroud)
不起作用,它会产生
windows is note defined错误if (this.mq() === 'small')
这完美地工作,pure Vue.js但我知道它在 Nuxt.js 上不起作用,因为它是服务器端渲染,它非常有意义,但我怎样才能让它工作呢?
我得到的最接近的是将样式代码移动到方法中mounted或将样式代码包装在 中if (process.client) {...},但任何替代方案都会在内容中生成特定的delay,jump例如:
process.client 与没有 process.client 的比较
使用 process.client 条件时在布局上跳转/延迟
我怎样才能让它立即工作?我怎样才能在安装 Vue.js 的默认行为之前获得屏幕宽度?
我怀疑这是因为 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*/ }
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
关于延迟,它有点“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>
Run Code Online (Sandbox Code Playgroud)
或者,当 css 应用于下一次 DOM 更新时,您可以将 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>
Run Code Online (Sandbox Code Playgroud)
但是,从您的问题来看,您似乎想应用响应式布局。最好的方法是将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>
Run Code Online (Sandbox Code Playgroud)
顺便说一句,作为旁注,请对计算属性完整使用正确的 if/else 语句。使用类似的东西if (!process.client) return { /* empty style object */}有时会在 Vue 计算属性中产生一些意想不到的行为。
这是一个由于服务器渲染而发生的老问题,如 github 上的以下问题所述。
.vue 文件
<script>
if (process.browser) {
require('aframe')
}
export default {
}
</script>
Run Code Online (Sandbox Code Playgroud)
nuxt.config.js
build: {
vendor: ['aframe']
}
Run Code Online (Sandbox Code Playgroud)
参考:
https://github.com/nuxt/nuxt.js/issues/30#issuecomment-264348589
https://nuxtjs.org/faq/window-document-undefined/
| 归档时间: |
|
| 查看次数: |
20375 次 |
| 最近记录: |