Vue는 여러 레이아웃 모드를 구현합니다.

1. 타겟 효과

        소스 코드 주소: multipal-layout-demo: vue2는 다중 레이아웃 + 다크 모드를 구현합니다.

기본 레이아웃: 헤더 너비 100%, 사이드바, 콘텐츠 영역

상단 레이아웃: 헤더 너비 100%, 콘텐츠 영역

사이드바 레이아웃: 사이드바 높이 100%, 헤더, 콘텐츠 영역

2. 원리 분석

(1) vuex 파일

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    // 暗黑模式
    isDark: false,
    // 布局类型
    layoutType: 'default'
  },
  mutations: {
    // 修改暗黑模式
    set_is_dark(state, val) {
      state.isDark = val
    },
    // 修改布局类型
    set_layout_type(state, val) {
      state.layoutType = val
    }
  },
  actions: {
  },
  modules: {
  }
})

        

(2) 레이아웃 썸네일은 어떻게 구현하나요? div + css를 사용하여 수동으로 레이아웃 스타일 구현

        부모 구성 요소는 레이아웃 유형의 배열을 전달하여 이 구성 요소를 순회합니다. 변수를 사용하여 인덱스 값을 저장하고 다른 레이아웃 유형 항목을 클릭할 때 인덱스를 전환하고 vuex에서 현재 선택된 레이아웃 유형을 수정합니다.

        축소판을 구성 요소로 캡슐화: Thumbnail.vue

<template>
    <!-- 缩略图 -->
    <div class="thumbnail">
        <div class="layout" v-for="(item, index) in layouts" @click="changeCheck(item, index)">
            <template v-if="item.type == 'default'">
                <div class="top" :style="{ background: isDark ? 'black' : '#fff' }"></div>
                <div class="left" :style="{ background: isDark ? 'black' : '#fff' }"></div>
            </template>
            <template v-if="item.type == 'top'">
                <div class="top" :style="{ background: isDark ? 'black' : '#fff' }"></div>
            </template>
            <template v-if="item.type == 'slide'">
                <div class="top"></div>
                <div class="left" :style="{ background: isDark ? 'black' : '#fff' }"></div>
            </template>

            <i class="el-icon-check" v-show="checked == index"></i>
        </div>
    </div>
</template>

<script>
import { mapState } from 'vuex'
export default {
    props: {
        // 布局类型数组
        layouts: {
            type: Array,
            default: () => []
        }
    },
    data() {
        return {
            // 当前选中值
            checked: 0,
        }
    },
    computed: {
        // 获取是否是暗黑模式,从而缩略图实现暗黑效果
        ...mapState(['isDark'])
    },
    methods: {
        // 切换选中值
        changeCheck(item, index) {
            this.checked = index
            this.$store.commit('set_layout_type', item.type)
        }
    }
}
</script>

<style lang="less" scoped>
.thumbnail {
    display: flex;
    width: 100%;

    .layout {
        position: relative;
        width: 50px;
        height: 50px;
        border: 1px solid gray;
        overflow: hidden;
        background: #f0f0f0;
        border-radius: 5px;
        cursor: pointer;

        .top {
            position: absolute;
            left: 0;
            top: 0;
            width: 100%;
            height: 25%;
        }

        .left {
            position: absolute;
            left: 0;
            top: 0;
            bottom: 0;
            width: 25%;
            height: 100%;
        }

        .el-icon-check {
            position: absolute;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
            font-size: 20px;
        }
    }
}
</style>

(3) 다양한 유형의 여러 레이아웃 파일 생성: 

 

 사이드바 레이아웃: src/views/layout/SlideLayout.vue

<template>
  <!-- 侧边栏布局 -->
  <div>
    <Sliderbar></Sliderbar>
    <Header></Header>
    <div class="content-box">
      <router-view />
    </div>
  </div>
</template>

<script>
import Sliderbar from '@/components/Sliderbar.vue'
import Header from '@/components/Header.vue'
export default {
  components: {
    Header,
    Sliderbar,
  },
}
</script>

<style lang="less" scoped></style>

기본 레이아웃 레이아웃: src/views/layout/DefaultLayout.vue 

<template>
  <!-- 默认布局 -->
  <div>
    <Header></Header>
    <Sliderbar></Sliderbar>
    <div class="content-box">
      <router-view />
    </div>
  </div>
</template>

<script>
import Header from '@/components/Header.vue'
import Sliderbar from '@/components/Sliderbar.vue'
export default {
  components: { Header, Sliderbar },
}
</script>

<style lang="less" scoped></style>

상단 레이아웃: src/views/layout/TopLayout.vue 

<template>
  <!-- 顶栏布局 -->
  <div>
    <Header></Header>
    <div class="content-box">
      <router-view />
    </div>
  </div>
</template>

<script>
import Header from '@/components/Header.vue'
export default {
  components: {
    Header,
  },
}
</script>

<style lang="less" scoped></style>

  

 (4) 홈 페이지 구성 요소인 Home.vue는 Home.vue 아래에 보조 경로를 렌더링합니다. 

 

<template>
    <!-- vuex获取选中的布局类型 -->
    <div>
        <defaultLayout v-show="layoutType == 'default'"></defaultLayout>
        <slideLayout v-show="layoutType == 'slide'"></slideLayout>
        <topLayout v-show="layoutType == 'top'"></topLayout>
    </div>
</template>

<script>
import defaultLayout from './layout/DefaultLayout.vue'
import slideLayout from './layout/SlideLayout.vue'
import topLayout from './layout/TopLayout.vue'
import { mapState } from 'vuex'

export default {
    components: { defaultLayout, slideLayout, topLayout },
    computed: {
        ...mapState(['layoutType'])
    },
}
</script>

<style lang="less" scoped></style>

 (5) 다크 모드와 레이아웃 타입 변수는 vuex에 모두 저장되어 있어 여러 컴포넌트 간의 데이터 통신이 더 편리합니다! mapState 를 통해 vuex 데이터를 가져온 다음 computed 를 통해 mapState 값을 수락 하지만 mapState 의 값을 직접 수정하려는 경우 다음 오류가 보고됩니다.

         계산된 속성 "isDark"가 할당되었지만 setter가 없습니다.

        이는 compute가 읽기 전용이기 때문입니다. 계산된 데이터는 직접 수정할 수 없으며 수정하려면 set을 사용하십시오.

  computed: {
    ...mapState(['isDark']),
    // computed property "isDark" was assigned to but it has no setter.  这是因为computed为只读的。不能直接修改computed的数据,要想修改则使用set
    darkMode: {
      get() {
        return this.isDark
      },
      set(val) {
        this.$store.commit('set_is_dark', val)
        // 获取html根元素标签
        let html = document.documentElement
        if (val) {
          // html添加class="dark"选择器
          html.classList.add('dark')
        } else {
          // html移除class="dark"选择器
          html.classList.remove('dark')
        }
      }
    }
  },

추천

출처blog.csdn.net/weixin_42375707/article/details/130312360