Я адаптировал руководство по параллаксу, которое я нашел в Интернете, для работы в моей ситуации, в основном я устранил необходимость жестко кодировать ширину и высоту контейнера параллакса, я предпочитаю, чтобы контент управлял этим.
Однако у меня возникают проблемы с ускорением и замедлением эффекта, так как увеличение числа отправляет изображение с экрана.
Я потратил часы на то, чтобы разобраться с расчетами, чтобы исправить это, но я изо всех сил, я добавил эффект ниже и преобразовал мои .vue файлы во встроенные компоненты.
Мне не удалось преобразовать мои * .vue-файлы во встроенные компоненты, появляется ошибка о том, что вычисленные свойства не определены, может кто-нибудь сказать мне, как решить эту проблему, чтобы основная проблема могла бытьрешен?
Ожидаемый результат
Имеет компонент Vue, который добавляет эффект параллакса в div, чтобы CSS мог контролировать фон и добавлять контент.Но также есть регулируемая скорость прокрутки для эффекта параллакса.
Фактический результат
Эффект параллакса, когда для значения factor
установлено значение 0.5
, но изображение уходит с экрана, например, при установке высоты на 0.9
, что должно вызвать появление изображениячтобы прокрутить больше.
const ParallaxElement = Vue.component('ParallaxElement', {
inject: ['parallaxContainer'],
props: {
factor: {
default: 0.25,
type: Number,
},
},
computed: {
offset() {
const {
height,
scrollFactor
} = this.parallaxContainer;
// The offset is relative to the height of
// the element. This means, if the factor is
// 0.5, the element is moved half its height
// over the full scroll distance of the viewport.
return scrollFactor * (height / 2) * this.factor;
}
},
template: `
<div :style="{ transform: translate3d(0, ${offset}px, 0) }" class="ParallaxElement">
<slot></slot>
</div>
`
});
const ParallaxImage = Vue.component('ParallaxImage', {
name: 'ParallaxImage',
components: {
ParallaxElement,
},
props: {
factor: {
default: 0.5,
type: Number,
},
},
data() {
return {
innerHeight: 0,
width: 0,
height: 0
};
},
computed: {
aspectRatio() {
return this.height / 2;
},
compensatedFactor: function() {
// Because the parallax effect is relative
// to the containers height and because we
// shrink the containers height by the given
// factor, we have to compensate this by
// increasing the factor.
return this.factor * 2;
},
compensatedHeight: function() {
// We want the image to scroll inside of a
// container to prevent the image scrolling
// above its sourounding elements. The
// container must be shrinked by the given
// factor to make sure we don't have any
// whitespace when scrolling.
return this.innerHeight - (this.innerHeight * this.factor);
},
template: `
<div :style="{ height: ${compensatedHeight}px }" class="parallax__image">
<ParallaxElement :factor="compensatedFactor" :style="{ paddingTop: ${aspectRatio}% }" class="parallax__aspect-ratio-wrap" >
<div ref="inside" class="parallax__aspect-ratio-inside">
<slot></slot>
</div>
</ParallaxElement>
</div>
`
},
mounted() {
this.height = this.$parent.$el.getBoundingClientRect().height;
this.width = this.$parent.$el.getBoundingClientRect().width;
this.$nextTick(() => {
this.setInnerHeight();
});
const eventHandler = () => requestAnimationFrame(this.setInnerHeight);
window.addEventListener('resize', eventHandler);
this.$on('hook:destroyed', () => {
window.removeEventListener('resize', eventHandler);
});
},
methods: {
setInnerHeight() {
this.innerHeight = this.$refs.inside.getBoundingClientRect().height;
},
},
});
const ParallaxContainer = Vue.component('parallax', {
name: 'ParallaxContainer',
provide() {
return {
parallaxContainer: this.data,
};
},
data() {
return {
data: {
height: 0,
scrollFactor: 0,
width: 0,
},
};
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>',
mounted() {
this.calcParallax();
// We're using a `requestAnimationFrame()`
// for optimal performance.
const eventHandler = () => requestAnimationFrame(this.calcParallax);
window.addEventListener('resize', eventHandler);
window.addEventListener('scroll', eventHandler);
// Remove the scroll hanlder when the
// component is destroyed.
this.$on(`hook:destroyed`, () => {
window.removeEventListener('resize', eventHandler);
window.removeEventListener('scroll', eventHandler);
});
this.$nextTick(() => {
requestAnimationFrame(this.calcParallax);
});
},
methods: {
calcParallax() {
const containerRect = this.$el.getBoundingClientRect();
this.data.height = containerRect.height;
this.data.width = containerRect.width;
const viewportOffsetTop = containerRect.top;
const viewportOffsetBottom = window.innerHeight - viewportOffsetTop;
this.data.scrollFactor = viewportOffsetBottom / (window.innerHeight + this.data.height);
},
},
template: `
<div class="ParallaxContainer">
<slot></slot>
</div>
`
});
Vue.component('parallax', {
components: {
ParallaxContainer,
ParallaxElement,
ParallaxImage
}
});
new Vue('#app');
.parallax__overlay {
position: relative;
z-index: 2;
padding: 30px 0;
box-sizing: border-box;
}
.parallax__image {
position: absolute;
top: 0;
width: 100%;
z-index: 1;
height: 100%;
background-size: cover;
background: url('https://i.ytimg.com/vi/pXs8DFC9ALw/maxresdefault.jpg') center center no-repeat;
}
.html1 {
margin-top: 120vh;
margin-bottom: 120vh;
display:block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id='app'>
<parallax class="app row-block html1">
<div class="parallax__overlay">
<div class="wrapper">
<div class="container">
<div class="row">
<h1>Welcome to <span>Somewhere</span></h1>
<h2>Simple. Friendly. Affordable</h2>
<a href="#" class="button" title="Visit our showroom">Visit Our Showroom</a>
</div>
</div>
</div>
</div>
<parallax-image :factor="0.5">
<div class="image"></div>
</parallax-image>
</parallax>
</div>