sourcecode

검색 중에 로드 아이콘을 추가하는 방법(Vue.js 2)

copyscript 2022. 8. 1. 22:40
반응형

검색 중에 로드 아이콘을 추가하는 방법(Vue.js 2)

내 컴포넌트는 다음과 같습니다.

<template>
    ...
        <input type="text" class="form-control" v-model="rawFilter" placeholder="Search" @keyup="getPlayers">
    ...
</template>

<script>
    import _ from 'lodash'
    ...
    export default {
        ...
        data() {
            return{
                msg:'hello vue',
                rawFilter:'',
                loading:false
            }
        },
        ...
        methods: {
            getPlayers: _.debounce(function(e) {
                const text = e.target.value.trim()
                this.$store.dispatch('getPlayers', {
                  q: text
                })
            },1000),
            ...
        }
    }
</script>

검색할 때 데이터를 표시하기 전에 로드 아이콘을 추가하고 싶다.

vue.js 2에서는 어떻게 하면 좋을까요?

사용하기 쉽도록 vuex 상태가 있는 로더를 사용하는 것이 좋습니다.

  1. 이를 통해 모든 컴포넌트에서 제어할 수 있습니다.
  2. 간단한 함수 호출로 쉽게 사용할 수 있습니다.
  3. 자연스럽게 소품이나 이벤트를 피하세요.

먼저 특정 로더가 필요한 위치를 정의합니다.

  1. 모든 api 호출에 사용됩니까?
  2. 브라우저 부하가 높은 작업(로드된 파일 처리 등)
  3. 또는 보다 구체적인 내용(사용자가 로그인을 시도할 때만 로더를 표시할 수 있음)

로더가 케이스 1과 같이 컴포넌트에 단단히 결합되어 있지 않은 경우.그러면 로더를 메인 vue 파일에 보관하는 것이 좋습니다(vue-cli를 사용하는 경우 App.vue).

뭐 이런 거:

<template>
  <div id="app">
    <loader></loader>
    <router-view></router-view>
  </div>
</template>

<script>
import Loader from './components/shared/loader/Loader'

export default {
  name: 'app',
  components: {
    Loader
  }
}
</script>

이 기능을 사용하면 로더를 추가할 필요가 없습니다.다른 모든 컴포넌트 파일에 vue를 추가합니다.하지만 먼저 사용 중인 로더 구성 요소와 스토어를 보여 드리겠습니다.

<template>
  <div class='loader-container' :class='{"show": show, "hidden": !show}'>
    <div class="curved-div">
      <div class="colour-magic">
        <i class='fa fa-circle-o-notch rotate'></i>
      </div>
      <div class="loading">
        {{ loading }}
      </div>
    </div>
  </div>
</template>

<script>
import { mapGetters } from 'vuex'
import * as NameSpace from '../../../store/NameSpace'

export default {
  data () {
    return {
      loading: 'Loading...'
    }
  },
  computed: {
    ...mapGetters({
      show: NameSpace.GET_LOADER_STATE
    })
  }
}
</script>

<style scoped>
.loader-container {
  position: fixed;
  width: 100%;
  height: 100%;
  background: rgba(0,0,0,0.8);
}

.curved-div {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translateX(-50%);
  border-radius: .3rem;
  width: 20rem;
  padding:1rem;
  background: white;
  box-shadow: 0 0 .1rem #fefefe;
}

.curved-div > * {
  display: inline-block;
}

.rotate {
  border-radius: 50%;
  padding: .5rem;
  animation-name: rotate;
  animation-duration: .7s;
  animation-iteration-count: infinite;
  animation-delay: 0s;
}

.loading {
  text-align: center;
  width: 12rem;
  font-size: 1.8rem;
}

.show {
  visibility: visible;
  opacity: 1;
  z-index: 1;
  transition: opacity 0.5s ease-out, visibility 0.5s ease-out, z-index 0.5s ease-out;
}

.hidden {
  opacity: 0;
  visibility: hidden;
  z-index: 0;
  transition: opacity 0.5s ease-out, visibility 0.5s ease-out, z-index 0.5s ease-out;
}

@keyframes rotate {
  0% {
    transform: rotateZ(0deg);
  }
  100% {
    transform: rotateZ(360deg);
  }
}

.colour-magic {
  animation-name: colorMagic;
  animation-duration: 20s;
  animation-iteration-count: infinite;
  animation-delay: 0s;
}

@keyframes colorMagic {
  0% { color: rgb(179,10,10); }
  10% { color: rgb(227,132,22); }
  20% { color: rgb(164,153,7); }
  30% { color: rgb(26,171,19); }
  40% { color: rgb(19,144,177); }
  50% { color: rgb(14,16,221); }
  60% { color: rgb(27,9,98); }
  70% { color: rgb(58,11,111); }
  80% { color: rgb(126,14,129); }
  90% { color: rgb(208,19,121); }
  100% { color: rgb(198,18,18); }
}
</style>

로더에는 폰트 어썸을 사용하고 있습니다.

매장은 다음과 같습니다.

import * as NameSpace from '../NameSpace'
// you can also use the namespace: true in your store and eliminate the need of NameSpace.js    

const state = {
  [NameSpace.LOADER_STATE]: false
}

const getters = {
  [NameSpace.GET_LOADER_STATE]: state => {
    return state[NameSpace.LOADER_STATE]
  }
}

const mutations = {
  [NameSpace.MUTATE_LOADER_STATE]: (state, payload) => {
    state[NameSpace.LOADER_STATE] = payload
  }
}

const actions = {
  [NameSpace.LOADER_SHOW_ACTION]: ({ commit }, payload) => {
    commit(NameSpace.MUTATE_LOADER_STATE, payload)
  }
}

export default {
  state,
  getters,
  mutations,
  actions
}

사용 예:

// This is not a .vue file it is a .js file, therefore a different way of using the store.
import Vue from 'vue'
import * as NameSpace from 'src/store/NameSpace'
import loaderState from 'src/store/modules/loader'

/**
* Pass the mutation function to reduce the text length
* This function can now be used in the api calls to start/stop the loader
* as the api starts and finishes.
*/
let loaderSwitch = loaderState.mutations[NameSpace.MUTATE_LOADER_STATE].bind(null, loaderState.state)

login (username, password) {
  loaderSwitch(true)
  return new Promise((resolve, reject) => {
    SomeEndpoint.logIn(username, password, {
      success (user) {
        loaderSwitch(false)
        resolve(user.attributes)
      },
      error (user, error) {
        loaderSwitch(false)
        reject(errorHelper(error.code))
      }
    })
  })

로그인을 사용하는 컴포넌트에 관계없이 로더 컴포넌트를 그대로 둘 필요가 없습니다.

깃발에 부착하여 사용하시면 됩니다.v-ifvue 리소스를 사용하는 경우,loading에서 사실로 표시하다before콜백하여 다시 설정하다false응답을 받은 후:

Vue 인스턴스

  methods: {
    loadData() {
      this.$http.get('/search', {
        before: () => {
          this.loading = true;
        }
      }).then(response => {
        // Deal with response
      }).then(() => {
          //set loading flag to false
          this.loading = false;
      })
    }
  },
  data: {
    loading: false
  }

HTML

<div id="app">
  <button @click="loadData">
    Get Data
  </button>

  <!-- Only show if loading is true -->
  <div v-if="loading" v-cloak>
    <i class="fa fa-circle-o-notch fa-spin fa-3x fa-fw"></i>
    <span>Loading...</span>
  </div>
</div>

JSFiddle은 다음과 같습니다.https://jsfiddle.net/hyeycoan/

템플릿에 loading div를 추가하고 다음 기준에 따라 표시를 전환할 수 있습니다.loading깃발 같은 거

new Vue({
  el: '#app',
  data: {
    show: true,
	isLoading: false,  
  },
	methods:{
		loadData: function(){
			this.isLoading = true;
			setTimeout(function(){
				this.isLoading = false;
			}.bind(this),1000);
		}
	}
})
.loading{
	display: none;
	position: absolute;
    width: 100%;
    height: 100%;
    top: 0;
    background: rgba(128, 128, 128, 0.5);
}
.loading.show{
	display: initial;
}
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
<div id="app">
	<div class="loading" v-bind:class="{ show: isLoading }">
		<span>Loading</span>
	</div>
	<button @click="loadData">Load</button>
</div>	
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>
</body>
</html>

로딩 인디케이터를 css로 예쁘게 만들 수도 있고 이미 사용 가능한 인디케이터를 사용할 수도 있습니다.예를 들어 http://tobiasahlin.com/spinkit/, http://loading.io/ 를 사용할 수도 있습니다.

언급URL : https://stackoverflow.com/questions/42454027/how-to-add-a-loading-icon-while-searching-vue-js-2

반응형