IT이야기

Vue js 각 개별 요소의 클래스 전환

cyworld 2022. 5. 10. 22:26
반응형

Vue js 각 개별 요소의 클래스 전환

부에즈에는 토글 클래스의 예가 많지만, 요소의 범위를 좁히는 토글 클래스는 아직 찾지 못했다.다음과 같은 전역 변수를 정의하는 경우:

data: {
  toggle: false
}

다음 탐색 모음과 같은 요소가 있으면 문제가 발생할 수 있음:

<ul class="menu">
  <li class="has-dropdown" v-bind:class="{ 'is-open': toggle }" @click="toggle = !toggle">
    Foo
    <ul class="dropdown">
      <li>Dropdown Item 1</li>
      <li>Dropdown Item 2</li>
    </ul>
  </li>
  <li class="has-dropdown" v-bind:class="{ 'is-open': toggle }" @click="toggle = !toggle">
    Bar
    <ul class="dropdown">
      <li>Dropdown Item 1</li>
      <li>Dropdown Item 2</li>
    </ul>
  </li>
</ul>

여기서 무슨 일이 일어나는지 봐?이 두 요소 중 하나를 클릭하면 클래스가 글로벌 변수를 변경하기 때문에 클래스가 동시에 전환됩니다.클릭되는 요소만 클래스를 어떻게 전환하시겠습니까?

너무나 단순한 것이 현대적인 프레임워크를 사용하여 너무나 많은 코드를 필요로 한다는 것이 내 마음을 어지럽히고, 그것이 자바스크립트 개발이 이렇게 복잡해지는 이유다.나는 그 문제를 해결하기 위해 평범한 자바스크립트 청취자를 이용했다.

<li class="has-dropdown" @click="toggle">
    ...
</li>
...

methods: {
 toggle: function( event ) {
   event.target.classList.toggle('is-open')
 }
}

...

이것은 그의 대답에서 @SLAKS가 언급했던 것의 작은 예일 뿐이다.본질적으로 목록 요소들을 그들 자신의 구성 요소로 바꾸어 그들 자신의 상태를 가질 수 있게 한다.

Vue.component("clicktoggle", {
  template:`<li :class="{ 'is-open': toggle }" @click="toggle = !toggle"><slot></slot></li>`,
  data() {return {toggle: false}}
})

그리고 이것이 어떻게 사용되는가.

console.clear()

Vue.component("clicktoggle", {
  template:`<li :class="{ 'is-open': toggle }" @click="toggle = !toggle"><slot></slot></li>`,
  data() {return {toggle: false}}
})

new Vue({
  el:"#app"
})
.has-dropdown {
  cursor: pointer;
}
.has-dropdown:not(.is-open) ul {
  display: none
}
<script src="https://unpkg.com/vue@2.2.6/dist/vue.js"></script>
<div id="app">
  <ul class="menu">
    <li class="has-dropdown" is="clicktoggle">
      Foo
      <ul class="dropdown">
        <li>Dropdown Item 1</li>
        <li>Dropdown Item 2</li>
      </ul>
    </li>
    <clicktoggle class="has-dropdown">
      Bar
      <ul class="dropdown">
        <li>Dropdown Item 1</li>
        <li>Dropdown Item 2</li>
      </ul>
    </clicktoggle>
  </ul>
</div>

Vue는 이와 같은 작은 구성 요소들을 없앤다는 것이 믿을 수 없을 정도로 간단하다.한 가지 빠른 개선은 전환하려는 클래스를 지정하기 위해 속성을 추가하는 것이다.

VueJS(및 대부분의 다른 현대 웹 프레임워크)의 기본 지침 원칙은 모든 것이 모델에서 나온다는 것이다.

당신은 결코 DOM 조작에 대해 말하지 않고, 대신에 당신이 원하는 효과를 설명하는 모델을 만든다.

네 경우엔, 두 개를 원한다는 뜻이야data한 가지가 아닌 재산.

그러나 실제로 해야 할 일은 각 목록 항목을 자신의 하위 구성 요소(그 다음 고유한 모델을 얻게 됨)로 만드는 것이다.슬롯을 사용하여 각 슬롯에 서로 다른 내용을 지정하십시오.

내가 이것을 다루는 방법은 부울이 아니라 색인(숫자 또는 기타)을 사용하는 것이다.확인toggle === index및 클릭 시 인덱스 또는 -1로 전환 설정


문자열 값을 토글로 사용하는 작업 버전

https://jsfiddle.net/dnqp2nc9/1/

new Vue({
  el: '#app',
  data: {
		toggle: null
  }
})
.has-dropdown li{
  opacity: 0.2;
}
.is-open li{
  opacity: 1;
}
<script src="https://unpkg.com/vue"></script>

<div id="app">
  {{toggle}}
  <ul class="menu">
    <li class="has-dropdown" v-bind:class="{ 'is-open': toggle === 'foo' }" @click="toggle = toggle !== 'foo' ? 'foo' : null">
      Foo [{{toggle === 'foo' ? 'open' : 'closed'}}]
      <ul class="dropdown">
        <li>Dropdown Item 1</li>
        <li>Dropdown Item 2</li>
      </ul>
    </li>
    <li class="has-dropdown" v-bind:class="{ 'is-open': toggle === 'bar' }" @click="toggle = toggle !== 'bar' ? 'bar' : null">
      Bar [{{toggle === 'bar' ? 'open' : 'closed'}}]
      <ul class="dropdown">
        <li>Dropdown Item 1</li>
        <li>Dropdown Item 2</li>
      </ul>
    </li>
  </ul>
</div>

여러 개를 열거나 닫으려면 어레이 버전 https://jsfiddle.net/hLm82x1d/1/을 참조하십시오.

new Vue({
  el: '#app',
  data: {
		toggle: []
  },
  methods: {
  	toggleItem: function (key) {
    	var i = this.toggle.indexOf(key)
    	if (i < 0) {
      	this.toggle.push(key)
      } else {
      	this.toggle.splice(i, 1)
      }
    }
  }
})
.has-dropdown li{
  opacity: 0.2;
}
.is-open li{
  opacity: 1;
}
<script src="https://unpkg.com/vue"></script>

<div id="app">
  {{toggle}}
  <ul class="menu">
    <li class="has-dropdown" v-bind:class="{ 'is-open': toggle.indexOf('foo') >= 0 }" @click="toggleItem('foo')">
      Foo [{{toggle === 'foo' ? 'open' : 'closed'}}]
      <ul class="dropdown">
        <li>Dropdown Item 1</li>
        <li>Dropdown Item 2</li>
      </ul>
    </li>
    <li class="has-dropdown" v-bind:class="{ 'is-open': toggle.indexOf('bar') >= 0 }" @click="toggleItem('bar')">
      Bar [{{toggle === 'bar' ? 'open' : 'closed'}}]
      <ul class="dropdown">
        <li>Dropdown Item 1</li>
        <li>Dropdown Item 2</li>
      </ul>
    </li>
  </ul>
</div>

이것은 나에게 효과가 있었던 것 같다. 아이디어는 데이터를 통해 토글하는 아동 구성요소로 드롭 다운을 하는 것이었다. 이것은 여전히 진행 중이지만, 나는 Js와 Vue를 배우는데 이것이 최선의 방법이 아닐 수도 있다.

프라이머리.부에를 하다

<template>
  <nav class="navbar navbar-expand-lg navbar-light bg-light">
    <div class="container-fluid">
      <nuxt-link class="navbar-brand" to="/">Navbar</nuxt-link>
      <button
        @click="isNavbarCollapsed = !isNavbarCollapsed"
        ref="navbar-toggler"
        :aria-expanded="[!isNavbarCollapsed ? 'true' : 'false']"
        :class="{ collapsed: isNavbarCollapsed}"
        class="navbar-toggler"
        type="button"
        data-toggle="collapse"
        data-target="#navbarNavDropdown"
        aria-controls="navbarNavDropdown"
        aria-label="Toggle navigation"
      >
        <span class="navbar-toggler-icon"></span>
      </button>
      <div 
        :class="{ show: !isNavbarCollapsed}"
        class="collapse navbar-collapse" 
        id="navbarNavDropdown"
      >
        <NavbarNav :items="loadedPrimaryMenu" />
      </div>
    </div>
  </nav>
</template>

<script>
import NavbarNav from '@/components/Navigation/ThePrimary/NavbarNav'

export default {
  name: 'TheNavigationPrimary',
  data() {
    return {
      isNavbarCollapsed: true
    }
  },
  computed: {
    loadedPrimaryMenu() {
      return this.$store.getters.loadedPrimaryMenu
    }
  },
  components: {
    NavbarNav
  }
}
</script>

<style scoped lang="scss">


</style>

나바나브뷰

 <template>
  <ul class="navbar-nav">
    <li
      v-for="item in items"
      :key="item.id"
      class="nav-item"
      :class="{ dropdown: hasChildren(item.children) }"
    >
      <NavLink
        v-if="!hasChildren(item.children)" 
        :attributes="item"
      />
      <NavbarNavDropdownMenu
        v-else
        :item="item"
      />
    </li>
  </ul>
</template>

<script>
import NavbarNavDropdownMenu from "@/components/Navigation/ThePrimary/NavbarNavDropdownMenu";
import NavLink from '@/components/Navigation/NavLink';

export default {
  name: "NavbarNav",
  props: {
    items: {
      type: Array,
      required: true,
    },
  },
  data() {
    return {
    };
  },
  methods: {
    hasChildren(item) {
      return item.length > 0 ? true : false;
    },
  },
  components: {
    NavbarNavDropdownMenu,
    NavLink
  }
};
</script>

<style scoped lang="scss">

</style>

NavbarNavDropdownMenu.부에를 하다

<template>
  <span v-if="item">
    <nuxt-link
      to="#"
      @click.prevent.native="openDropdownMenu"
      v-click-outside="closeDropdownMenu"
      :title="item.title"
      :class="[
        item.cssClasses, 
        { show: isDropdownMenuVisible }
      ]"
      :id="`navbarDropdownMenuLink-${item.id}`"
      :aria-expanded="[isDropdownMenuVisible ? true : false]"
      class="nav-link dropdown-toggle"
      aria-current="page"
      role="button"
      data-toggle="dropdown"
    >
      {{ item.label }}
    </nuxt-link>
    <ul
      :class="{ show: isDropdownMenuVisible }"
      :aria-labelledby="`navbarDropdownMenuLink-${item.id}`"
      class="dropdown-menu"
    >
      <li v-for="item in item.children" :key="item.id">
        <NavLink
          :attributes="item"
          class="dropdown-item"
        />
      </li>
    </ul>
  </span>
</template>

<script>
import NavLink from '@/components/Navigation/NavLink';

export default {
  name: "DropdownMenu",
  props: {
    item: {
      type: Object,
      required: true,
    },
  },
  data() {
    return {
      isDropdownMenuVisible: false,
    };
  },
  methods: {
    openDropdownMenu() {
      this.isDropdownMenuVisible = !this.isDropdownMenuVisible;
    },

    closeDropdownMenu() {
        this.isDropdownMenuVisible = false;
    }
  },
  components: {
    NavLink
  }
};
</script>

<style scoped lang="scss">

</style>

NavLink.부에를 하다

 <template>
  <component
    v-bind="linkProps(attributes.path)"
    :is="attributes"  
    :title="attributes.title"
    :class="[ attributes.cssClasses ]"
    class="nav-link active"
    aria-current="page"
    prefetch
  >
  {{ attributes.label }}
  </component>
</template>

<script>
export default {
  name: 'NavLink',
  props: {
    attributes: {
      type: Object,
      required: true
    }
  },
  methods: {
    linkProps (path) {
      if (path.match(/^(http(s)?|ftp):\/\//) || path.target === '_blank') {
        return {
          is: 'a',
          href: path,
          target: '_blank',
          rel: 'noopener'
        }
      }
      return {
        is: 'nuxt-link',
        to: path
      }
    }
  }
}
</script>

<style scoped lang="scss">

</style>

외부 클릭 시 드롭다운을 닫으려면

import Vue from 'vue'

Vue.directive('click-outside', {
  bind: function (el, binding, vnode) {
    el.clickOutsideEvent = function (event) {
      if (!(el == event.target || el.contains(event.target))) {
        vnode.context[binding.expression](event);
      }
    };
    document.body.addEventListener('click', el.clickOutsideEvent)
  },
  unbind: function (el) {
    document.body.removeEventListener('click', el.clickOutsideEvent)
  },
});

참조URL: https://stackoverflow.com/questions/45697058/vue-js-toggle-class-of-each-individual-element

반응형