Skip to content

Commit ce65fa7

Browse files
felixdenoixSlgoetz
andauthored
Improve Vue lifecycle integration (#5)
* Improve vue lifecycle usage * Update .editorconfig and ran lint to comply with nuxt code style * removed unused * upgraded packages * lock update --------- Co-authored-by: Simon Goetz <simon@milkshake.studio>
1 parent cffc496 commit ce65fa7

File tree

9 files changed

+1746
-1518
lines changed

9 files changed

+1746
-1518
lines changed

.editorconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
root = true
22

33
[*]
4-
indent_size = 3
4+
indent_size = 2
55
indent_style = space
66
end_of_line = lf
77
charset = utf-8

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "nuxt-lenis",
3-
"version": "1.0.3",
3+
"version": "1.0.4",
44
"license": "MIT",
55
"type": "module",
66
"repository": {

playground/app.vue

Lines changed: 25 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,35 @@
11
<template>
2-
<lenis id="test" ref="lenisRef" :options="vsOptions" @scroll="scrollEmitter">
3-
<h1>hello world</h1>
4-
<div />
5-
<div />
6-
<div />
7-
<div />
8-
<div />
9-
<div />
10-
<div />
11-
<div />
12-
<div />
13-
<div />
14-
<div />
15-
<div />
16-
<div />
17-
</lenis>
2+
<div>
3+
<header>
4+
<h1>Nuxt Lenis scroller</h1>
5+
<nav>
6+
<nuxt-link to="/">
7+
Index
8+
</nuxt-link> &nbsp;
9+
<nuxt-link to="/about">
10+
About
11+
</nuxt-link>
12+
</nav>
13+
</header>
14+
<nuxt-page />
15+
</div>
1816
</template>
1917

2018
<script setup>
21-
import { ref, inject, watch, onMounted } from 'vue'
22-
const scrollState = inject('scrollState')
23-
const lenisRef = ref(null)
24-
const vsOptions = ref({
25-
duration: .2,
26-
direction: 'Horizontal',
27-
touchMultiplier: 20,
28-
infinite: false
29-
})
3019
31-
watch(scrollState, async (val) => {
32-
console.log('scrollState', val)
33-
})
34-
35-
const scrollEmitter = (val) => {
36-
console.log('scrollEmitter', val)
37-
}
38-
39-
onMounted(() => {
40-
console.log('ref', lenisRef.value)
41-
})
4220
</script>
4321

4422
<style>
45-
#test div {
46-
height: 50vh;
47-
margin-bottom: 300px;
48-
background: red;
49-
width: 100%;
23+
* {
24+
box-sizing: border-box;
25+
}
26+
div {
27+
padding: 10px;
28+
}
29+
30+
header {
31+
display: flex;
32+
justify-content: space-between;
33+
align-items: baseline;
5034
}
5135
</style>

playground/components/BaseChild.vue

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<script setup>
2+
const props = defineProps({
3+
height: {
4+
type: String,
5+
default: '10vh',
6+
},
7+
color: {
8+
type: String,
9+
default: 'rebeccaPurple'
10+
}
11+
})
12+
</script>
13+
14+
<template>
15+
<div>
16+
<p>I'm the BaseChild component. My color and height can change based on my props</p>
17+
</div>
18+
</template>
19+
20+
<style scoped>
21+
div {
22+
padding: 10px;
23+
width: 50vw;
24+
height: v-bind(props.height);
25+
background-color: v-bind(props.color);
26+
}
27+
</style>

playground/pages/about.vue

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<script>
2+
</script>
3+
4+
<template>
5+
<div>
6+
<h2>About page</h2>
7+
<p>
8+
nothing special around here, just a page to trigger the lenis component lifecycle methods on the index page.
9+
</p>
10+
</div>
11+
</template>
12+
13+
<style scoped>
14+
</style>

playground/pages/index.vue

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<template>
2+
<lenis
3+
id="test"
4+
ref="lenisRef"
5+
:options="vsOptions"
6+
@scroll="scrollEmitter">
7+
<h2>Index Page</h2>
8+
9+
<p>Playground for lenis scroll plugin for nuxt</p>
10+
11+
<div>
12+
<p>
13+
A little select to trigger the onUpdate hook in the lenis component and trigger the resize method on the lenis
14+
instance :
15+
<select
16+
id="selectedBaseChildOption"
17+
v-model="selectedBaseChildOption"
18+
name="selectedBaseChildOption"
19+
>
20+
<option v-for="(_, idx) in baseChildOptions" :key="_" :value="idx">
21+
{{ _.height }} - {{ _.color }}
22+
</option>
23+
</select>
24+
</p>
25+
<BaseChild v-bind="baseChildOptions[selectedBaseChildOption]" />
26+
</div>
27+
28+
<div />
29+
<div />
30+
<div />
31+
32+
<div class="fixed">
33+
<button @click="changeOptions">
34+
Change scrollOptions
35+
</button>
36+
<button @click="showScrollSstate = !showScrollSstate">
37+
{{ showScrollSstate ? 'hide' : 'show' }} scrollState
38+
</button>
39+
<div v-if="showScrollSstate">
40+
<pre class="nopointer">{{
41+
scrollState
42+
}}</pre>
43+
</div>
44+
</div>
45+
</lenis>
46+
</template>
47+
48+
<script setup>
49+
import { ref, reactive, inject, watch, onMounted } from 'vue'
50+
import BaseChild from '../components/BaseChild'
51+
52+
const scrollState = inject('scrollState')
53+
const lenisRef = ref(null)
54+
const vsOptions = reactive({
55+
duration: 0.2,
56+
direction: 'Horizontal',
57+
touchMultiplier: 20,
58+
infinite: false
59+
})
60+
61+
const baseChildOptions = [
62+
{
63+
height: '10vh',
64+
color: 'rebeccapurple'
65+
},
66+
{
67+
height: '80vh',
68+
color: 'lime'
69+
},
70+
{
71+
height: '180vh',
72+
color: 'yellow'
73+
}
74+
]
75+
const selectedBaseChildOption = ref(0)
76+
const showScrollSstate = ref(false)
77+
78+
watch(scrollState, (val) => {
79+
console.log('scrollState', val)
80+
})
81+
82+
watch(vsOptions, (newVal) => {
83+
console.log('vsOptions newVal', newVal)
84+
})
85+
86+
const scrollEmitter = (val) => {
87+
console.log('scrollEmitter', val)
88+
}
89+
90+
const changeOptions = () => {
91+
console.log('🐯 changing options')
92+
vsOptions.duration = vsOptions.duration > 5 ? 0.1 : 10
93+
}
94+
95+
onMounted(() => {
96+
console.log('Lenis Component ref :', lenisRef.value)
97+
})
98+
</script>
99+
100+
<style>
101+
#test>div {
102+
min-height: 50vh;
103+
margin-bottom: 300px;
104+
background: red;
105+
width: 100%;
106+
}
107+
108+
.fixed {
109+
position: fixed;
110+
top: 100px;
111+
right: 20px;
112+
max-width: 50vw;
113+
background-color: rgba(255, 255, 255, 0.718);
114+
border: 1px solid #000;
115+
display: flex;
116+
flex-direction: column;
117+
align-items: flex-end;
118+
}
119+
120+
.nopointer {
121+
pointer-events: none;
122+
}
123+
</style>

src/module.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { fileURLToPath } from 'url'
21
import {
32
addComponent,
43
defineNuxtModule,
@@ -22,7 +21,7 @@ export default defineNuxtModule<ModuleOptions>({
2221
defaults: {
2322
addPlugin: true
2423
},
25-
async setup (options, nuxt) {
24+
setup (options, nuxt) {
2625
const { resolve } = createResolver(import.meta.url)
2726
addImports([
2827
{

src/runtime/components/lenis.vue

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,69 +6,77 @@
66

77
<script>
88
import {
9+
computed,
910
defineComponent,
10-
ref,
11-
onMounted,
12-
onBeforeUnmount,
1311
inject,
12+
onBeforeUnmount,
13+
onMounted,
1414
onUpdated,
15-
reactive
15+
ref,
16+
toRefs,
17+
watch,
1618
} from "vue";
19+
1720
export default defineComponent({
1821
props: ["options"],
19-
setup({ options }, { emit }) {
22+
setup(props, { emit }) {
2023
const Lenis = inject("Lenis");
2124
const setScrollState = inject("setScrollState");
2225
const setLenis = inject("setLenis");
2326
const lenisVS = ref(0);
27+
const lenisRaf = ref(null);
2428
const lenisContent = ref(null);
29+
const {options} = toRefs(props)
30+
2531
/**
2632
* Starting options - for full list of options visit https://github.com/studio-freight/lenis
2733
*/
28-
const lenisOptions = reactive(
29-
Object.assign(
30-
{},
31-
{
32-
duration: 1.2,
33-
easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
34-
direction: "vertical",
35-
gestureDirection: "vertical",
36-
smooth: true,
37-
mouseMultiplier: 1,
38-
smoothTouch: false,
39-
touchMultiplier: 2,
40-
infinite: false,
41-
},
42-
options || {}
43-
)
44-
);
34+
const lenisOptions = computed(() => {
35+
return {
36+
duration: 1.2,
37+
easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
38+
direction: "vertical",
39+
gestureDirection: "vertical",
40+
smooth: true,
41+
mouseMultiplier: 1,
42+
smoothTouch: false,
43+
touchMultiplier: 2,
44+
infinite: false,
45+
...options.value
46+
}
47+
});
4548
4649
// On mounted set new Lenis instance
4750
onMounted(() => {
4851
initLenis();
4952
});
53+
5054
// Destroy on unmount
5155
onBeforeUnmount(() => {
5256
destroyLenis();
5357
});
5458
5559
onUpdated(() => {
5660
if (!lenisVS.value) return;
57-
lenisVS.value.off("scroll");
58-
lenisVS.value.destroy();
59-
lenisVS.value = new Lenis();
61+
if (!lenisOptions.autoResize) lenisVS.value.resize();
6062
});
6163
64+
watch(lenisOptions, (newVal) => {
65+
if (!lenisVS.value) return;
66+
destroyLenis();
67+
initLenis();
68+
})
69+
6270
const initLenis = () => {
6371
if (process.client) {
64-
lenisVS.value = new Lenis(lenisOptions);
72+
lenisVS.value = new Lenis(lenisOptions.value);
6573
lenisVS.value.on("scroll", (scrollData) => {
6674
setScrollState(scrollData);
6775
emit("scroll", scrollData);
6876
});
6977
setLenis(lenisVS.value);
7078
emit("initiated", { lenis: lenisVS.value });
71-
requestAnimationFrame(raf);
79+
lenisRaf.value = requestAnimationFrame(raf);
7280
} else {
7381
throw new Error("Process Client is false");
7482
}
@@ -85,7 +93,9 @@ export default defineComponent({
8593
setScrollState(false);
8694
lenisVS.value.off("scroll");
8795
lenisVS.value.destroy();
96+
cancelAnimationFrame(lenisRaf.value);
8897
};
98+
8999
return {
90100
destroyLenis,
91101
initLenis,

0 commit comments

Comments
 (0)