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') } } } },