• 카테고리

    질문 & 답변
  • 세부 분야

    프론트엔드

  • 해결 여부

    미해결

이런 질문도 답변 가능할까요?

22.04.20 16:01 작성 조회수 167

0

지금 16강 수강중이구요 스크롤 애니메이션을 vue에서 따라 작성해보고있는데 ..

값이 다르게 찍히는게 있어서 혹시나 해결방법을 아시는지 궁금해서 여쭤봅니다. ㅠㅠ

다른 부분들은 나름 어거지로??어떻게 따라와서 텍스트 하나를 나타나고 사라지게 하는게 되긴하는데 ...

추후 강의를 똑같이 따라갈 수 있을런지...

 

제 이슈는 이렇습니다.

value값이 동일하게 찍히질않습니다.

강의에서는 아래처럼 values.length값이 배열로 잘 나오는데..

 

저는 value값을 콘솔로 찍었을 때는 이렇게나오고

values[0]은 undefined로 나와버려서 length값 체크도못하고 calcValue함수 내에서도 이런식으로 작성하면서 따라했거든요 ..

object name을 콕 찝어서 데려와야만 배열값을 얻어요..

배열로얻어오지못하니 강의와 똑같이 구현해보려고 calcvalue함수를 copy해서 하나는 in 하나는 out으로하는

무지막지한 코드를 작성해놨어요🤯🤯

 

같은 자바스크립트인데 환경좀 다르다고 이렇게 value값이 다를일인가요...........

value의 배열값을 강의처럼 얻을수없다면 제 vue 스크롤연습은 여기서 접어야하는걸까요..?........ 이후 강의는 따라해볼 엄두가 안나네요 ..ㅜ 이틀 삽질하다 슬퍼서 질문올려봅니다...

full code남기며 ... 질문마무리하겠습니다🥺

 

<template>
  <div class="main" ref="scrollWrap">
    <section class="scroll-section" id="scroll-section-0" ref="scrollSection0">
      <div class="hero" :style="`background-image: url(${이미지})`">
        <div class="text-test">소환사 여러분</div>
        <div class="sticky-elem hero-message a" ref="message1">
          <div class="year">10th ANNIVERSARY</div>
        </div>
        <!-- <div class="sticky-elem hero-message b" ref="message2">
          <div class="thanks">THANK YOU SUMMONERS</div>
        </div>
        <div class="sticky-elem hero-message c" ref="message3">
          <div class="greeting">리그오브레전드와 10년간 함께 해주신 소환사 여러분, 감사합니다!</div>
          <div class="greeting">THANK YOU, SUMMONERS!</div>
        </div> -->
      </div>
    </section>
   <section class="scroll-section" id="scroll-section-1" ref="scrollSection1">
     <p>
       Lorem, ipsum dolor sit amet consectetur adipisicing elit. Assumenda<br>
     </p>
   </section>
   <button @click="setLayout">레이아웃d</button>
    <div>
      <input type="text" @input="setSearch($event.target.value)" />
      <button @click="searchForPlayer(e)">serach</button>
      <div v-if="playerData" class="box">
        <p>{{playerData.name}}</p>
        <p>{{playerData.summonerLevel}}</p>
        <p>{{playerData.profileIconId}}</p>
        <p><img width="100" height="100" :src="`http://ddragon.leagueoflegends.com/cdn/12.7.1/img/profileicon/${playerData.profileIconId}.png`"></p>
      </div>
      <div v-else class="box2">
        <p>{{noPlayer}}</p>
        <p>데이터가없습니다</p>
      </div>
    </div>

    <router-view></router-view>
    <router-link to="/JH">링크</router-link>

  </div>

</template>

<script>
  import { onMounted, ref} from 'vue'
  import axios from 'axios'

  //씬을나눈다
  //씬의 높이를 세팅한다
  //활성화 시킬 씬을 결정한다
   //this.prevScrollHeight = this.prevScrollHeight + this.sceneInfo[i].scrollHeight;
  //얘네는같은거임 this.prevScrollHeight += this.sceneInfo[i].scrollHeight;
  export default {
    name: 'App',
    components: {

    },
    data() {
      return {
        errorText: "존재하지않는 데이터입니다",
        이미지: "https://universe.leagueoflegends.com/images/championsBackground.jpg",
        sceneInfo: [
          {
            type: 'sticky',
            heightNum: 5,
            scrollHeight: 0,
            objs: {
              // container: document.querySelector('scroll-section-0')
              container : this.$refs.scrollSection0,
              massageA : this.$refs.message1,
              massageB : this.$refs.message2,
              massageC : this.$refs.message3,
            },
            values: {
               messageA_opacity_in: [0,1, {start: 0.1, end: 0.2}],
               messageA_opacity_out: [1,0, {start: 0.25, end: 0.3}],
            }
          },
          {
            type: 'normal',
            heightNum: 5,
            scrollHeight: 0,
            objs: {
               container: this.$refs.scrollSection1
            }
          },
        ],
        //window.pageYOffset 갱신
        yOffset : 0,
        //현재 스크롤 위치(yOffset)보다 이전에 위치한 스크롤 섹션들의 스크롤 높이값의 합
        prevScrollHeight : 0,
        //현재 활성화된 scene
        currentScene : 0,
        totalScrollHeight: 0,
        messageA_opacity_in: '',
        messageA_opacity_out: '',
        currentYOffset: 0,
        rv: 0,
        scrollRatio: 0,
        outerScrollRatio:0,
        enterNewScene: false,
        scrollHeight: 0,
        partSCrollStart: 0,
        partScrollEnd: 0,
        partScrollHeight: 0,
        currentSceneValues: '',
        infoCurretScene: 0,

      }
    },
    setup() {
      let searchText = ref("");
      let playerData = ref();
      let noPlayer = ref();
      let deleteMessage = ("존재하지않음");
      let playerId = ref([]);
      let apiKey = "RGAPI-62f8907f-eab8-4333-bc43-94d32a09be28";

      const setSearch = (검색어) => {
        searchText = 검색어
      }

      const searchForPlayer = () => {
        playerData.value = null
        noPlayer.value = null

        //Handle the API call
         axios.get(`https://kr.api.riotgames.com/lol/summoner/v4/summoners/by-name/${searchText}?api_key=${apiKey}`)
          .then((response) => {
            playerData.value = response.data

          }).catch(error => {
            playerData.value = null
            noPlayer.value = deleteMessage;
          });
      }

      return {
        searchText,
        playerData,
        playerId,
        setSearch,
        searchForPlayer,

      };
    },

    methods: {
      init() {
          this.setLayout();
          this.scrollLoop();

      },
      setLayout() {
          // Sticky Conainer 의 높이를 설정함.
          // for( let i = 0; i < this.sceneInfo.length; i++ ){
          //   this.sceneInfo[i].scrollHeight = this.sceneInfo[i].heightNum + window.innerHeight;
          //   this.sceneInfo[i].objs.container.style.height = `${this.sceneInfo[i].scrollHeight}px`;
          // }
          this.sceneInfo[0].scrollHeight = this.sceneInfo[0].heightNum + window.innerHeight;
          this.$refs.scrollSection0.style.height =  `${this.sceneInfo[0].scrollHeight}px`;

          this.sceneInfo[1].scrollHeight = this.sceneInfo[1].heightNum + window.innerHeight;
          this.$refs.scrollSection1.style.height =  `${this.sceneInfo[1].scrollHeight}px`;

          this.yOffset = window.pageYOffset;
          this.totalScrollHeight = 0;
          for( let i = 0; i < this.sceneInfo.length; i++ ){
            this.totalScrollHeight += this.sceneInfo[i].scrollHeight;
            if(this.totalScrollHeight >= this.yOffset){
              this.currentScene = i;
   
              break;
            }
          }
       },

       calcValues(values, currentYOffset){
        this.rv;

        this.scrollHeight = this.sceneInfo[this.currentScene].scrollHeight;
        //현재 scene에서 스크롤된 범위를 비율로 구하기
        this.scrollRatio = this.currentYOffset / this.scrollHeight;
        this.outerScrollRatio = (this.yOffset - this.prevScrollHeight) / this.scrollHeight;
        this.infoCurretScene = this.sceneInfo[this.currentScene];
        this.currentSceneValues =  this.sceneInfo[this.currentScene].values;

        if(this.currentSceneValues.messageA_opacity_in.length === 3){

           //start ~ end 사이에 애니메이션 실행
           this.partSCrollStart = this.currentSceneValues.messageA_opacity_in[2].start * this.scrollHeight;
           this.partScrollEnd = this.currentSceneValues.messageA_opacity_in[2].end * this.scrollHeight;
           this.partScrollHeight = this.partScrollEnd - this.partSCrollStart;

           if(this.currentYOffset >= this.partSCrollStart && this.currentYOffset <= this.partScrollEnd){
            this.rv = (this.currentYOffset - this.partSCrollStart) / this.partScrollHeight * ( this.currentSceneValues.messageA_opacity_in[1] -  this.currentSceneValues.messageA_opacity_in[0]) +  this.currentSceneValues.messageA_opacity_in[0];
           }else if(this.currentYOffset < this.partSCrollStart){
              this.rv = this.currentSceneValues.messageA_opacity_in[0];
           }else if(this.currentYOffset  > this.partScrollEnd){
             this.rv = this.currentSceneValues.messageA_opacity_in[1];
           }

         }else {
          this.rv = this.scrollRatio * ( this.currentSceneValues.messageA_opacity_in[1] -  this.currentSceneValues.messageA_opacity_in[0]) +  this.currentSceneValues.messageA_opacity_in[0];
         }

         return this.rv;
       },
        calcValues2(values, currentYOffset){
        this.rv;

        this.scrollHeight = this.sceneInfo[this.currentScene].scrollHeight;
        //현재 scene에서 스크롤된 범위를 비율로 구하기
        this.scrollRatio = this.currentYOffset / this.scrollHeight;
        this.outerScrollRatio = (this.yOffset - this.prevScrollHeight) / this.scrollHeight;
        this.infoCurretScene = this.sceneInfo[this.currentScene];
        this.currentSceneValues =  this.sceneInfo[this.currentScene].values;


        if(this.currentSceneValues.messageA_opacity_out.length === 3){

           //start ~ end 사이에 애니메이션 실행
           this.partSCrollStart = this.currentSceneValues.messageA_opacity_out[2].start * this.scrollHeight;
           this.partScrollEnd = this.currentSceneValues.messageA_opacity_out[2].end * this.scrollHeight;
           this.partScrollHeight = this.partScrollEnd - this.partSCrollStart;

           if(this.currentYOffset >= this.partSCrollStart && this.currentYOffset <= this.partScrollEnd){
            this.rv = (this.currentYOffset - this.partSCrollStart) / this.partScrollHeight * ( this.currentSceneValues.messageA_opacity_out[1] -  this.currentSceneValues.messageA_opacity_out[0]) +  this.currentSceneValues.messageA_opacity_out[0];
           }else if(this.currentYOffset < this.partSCrollStart){
              this.rv = this.currentSceneValues.messageA_opacity_out[0];
           }else if(this.currentYOffset  > this.partScrollEnd){
             this.rv = this.currentSceneValues.messageA_opacity_out[1];
           }

         }else {
          this.rv = this.scrollRatio * ( this.currentSceneValues.messageA_opacity_out[1] -  this.currentSceneValues.messageA_opacity_out[0]) +  this.currentSceneValues.messageA_opacity_out[0];
         }

         return this.rv;
       },

       playAnimation(){
        // const values = this.sceneInfo[this.currentScene].objs;
        // const values = this.sceneInfo[this.currentScene].values;
        this.currentYOffset = this.yOffset - this.prevScrollHeight;

        console.log(this.currentSceneValues[0]);


         switch (this.currentScene) {
           case 0:

            this.messageA_opacity_in = this.calcValues(this.sceneInfo[0].values.messageA_opacity_in,  this.currentYOffset);
            this.messageA_opacity_out = this.calcValues2(this.sceneInfo[0].values.messageA_opacity_out,  this.currentYOffset);

            if(this.outerScrollRatio <= 0.22){
              //in
              this.$refs.message1.style.opacity = this.messageA_opacity_in;
            } else {
              //out
              this.$refs.message1.style.opacity = this.messageA_opacity_out;
            }

             break;

           case 1:

             break;
         }
       },

       scrollLoop(){
         this.enterNewScene = false;
         //scrollHeight값 누적되지않도록 0으로
          this.prevScrollHeight = 0;
          for(let i = 0; i< this.currentScene; i++){
          this.prevScrollHeight += this.sceneInfo[i].scrollHeight;
        }

        if(this.yOffset > this.prevScrollHeight + this.sceneInfo[this.currentScene].scrollHeight){
          this.enterNewScene = true;
          this.currentScene++;
          //  this.$refs.scrollWrap.setAttribute('id', `show-scene-${this.currentScene}`);
        }

        if(this.yOffset < this.prevScrollHeight){
          if(this.currentScene === 0) return;
          this.enterNewScene = true;
          this.currentScene--;

          //  this.$refs.scrollWrap.setAttribute('id', `show-scene-${this.currentScene}`);
        }

        this.$refs.scrollWrap.setAttribute('id', `show-scene-${this.currentScene}`);

        if(this.enterNewScene) return;
        this.playAnimation();

       },
    },
    mounted() {
      this.init();

      window.addEventListener('DOMContentLoaded',this.setLayout);
      window.addEventListener('resize', this.setLayout);
      window.addEventListener('scroll', () =>{
        //스크롤이 일어날 때 yOffset 의 값을 window.pageYOffset 값으로 갱신
        this.yOffset = window.pageYOffset;
        this.scrollLoop();
      });

    },
  }
</script>

<style lang="scss">
  body {
    margin: 0;
  }

  .scroll-section {
    border: 1px solid red
  }

  .text-test {
    position: relative;
    padding: 20px;
    z-index: 1;
    color: red;
  }
</style>

 

답변 1

답변을 작성해보세요.

1

아이고 고생 많이 하셨네요^^;

playAnimation 함수에서 아래처럼 출력해보시면 제대로 나올 거예요~
아래 코드의 values, 즉 playAnimation에서 정의하는 values는 messageA_opacity_in, messageA_opacity_out과 같은 배열들을 속성으로 갖고 있는 오브젝트이고요(배열 아님),

const values = this.sceneInfo[this.currentScene].values;
console.log(values);
console.log('in length: ' + values.messageA_opacity_in.length)
console.log('out length: ' + values.messageA_opacity_out.length)

playAnimation 함수 안에서 calcValues 함수를 호출할 때
calcValues(values.messageA_opacity_in, currentYOffset);
이런 식으로 values의 messageA_opacity_in(배열)이나 messageA_opacity_out(배열)을 넣기 때문에,
calcValues 함수에서 사용되는 매개변수 values는 playAnimation 함수에서 넣어준 values.messageA_opacity_in 또는 values.messageA_opacity_out 등이 되는 거랍니다.

가뜩이나 예제가 좀 생각할 게 많은데 두 개의 다른 values가 이름이 같아서 코딩 하시다가 혼동하신게 아닌가 싶기도 하고 그러네요^^; 어떻게 보면 이름을 똑같이 한 제 잘못입니다 ㅠㅠ

김매력님의 프로필

김매력

2022.04.22

답변 감사합니다!