0


【若依】若依Vue3前端拆解分析--布局分析--index篇

若依Vue3前端拆解分析

布局分析 – Layout

这个是Layout的目录结构
layout
├─ index.vue  // 主文件
└─ components  // 组件目录
   ├─ AppMain.vue
   ├─ index.js
   ├─ Navbar.vue  // 顶部导航
   ├─ TagsView  // 标签组件
   │  ├─ index.vue
   │  └─ ScrollPane.vue
   ├─ Sidebar  // 侧边栏组件
   │  ├─ index.vue
   │  ├─ Link.vue
   │  ├─ Logo.vue
   │  └─ SidebarItem.vue
   ├─ Settings  // 右侧布局设置抽屉
   │  └─ index.vue
   ├─ InnerLink
   │  └─ index.vue
   └─ IframeToggle
      └─ index.vue

首先来看index主文件。

<template>
  <div :class="classObj" class="app-wrapper" :style="{ '--current-color': theme }">
    <div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
    <!-- 侧边栏 -->
    <sidebar v-if="!sidebar.hide" class="sidebar-container" />
    <div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide }" class="main-container">
      <div :class="{ 'fixed-header': fixedHeader }">
        <!-- 顶部导航 -->
        <navbar @setLayout="setLayout" />
        <!-- 标签页 -->
        <tags-view v-if="needTagsView" />
      </div>
      <app-main />
      <settings ref="settingRef" />
    </div>
  </div>
</template>

<script setup>
import { useWindowSize } from '@vueuse/core'
import Sidebar from './components/Sidebar/index.vue'
import { AppMain, Navbar, Settings, TagsView } from './components'
import defaultSettings from '@/settings'

import useAppStore from '@/store/modules/app'
import useSettingsStore from '@/store/modules/settings'

const settingsStore = useSettingsStore()
const theme = computed(() => settingsStore.theme);
const sideTheme = computed(() => settingsStore.sideTheme);
const sidebar = computed(() => useAppStore().sidebar);
const device = computed(() => useAppStore().device);
const needTagsView = computed(() => settingsStore.tagsView);
const fixedHeader = computed(() => settingsStore.fixedHeader);

const classObj = computed(() => ({
  hideSidebar: !sidebar.value.opened,
  openSidebar: sidebar.value.opened,
  withoutAnimation: sidebar.value.withoutAnimation,
  mobile: device.value === 'mobile'
}))

const { width, height } = useWindowSize();
const WIDTH = 992; // refer to Bootstrap's responsive design

watch(() => device.value, () => {
  if (device.value === 'mobile' && sidebar.value.opened) {
    useAppStore().closeSideBar({ withoutAnimation: false })
  }
})

watchEffect(() => {
  if (width.value - 1 < WIDTH) {
    useAppStore().toggleDevice('mobile')
    useAppStore().closeSideBar({ withoutAnimation: true })
  } else {
    useAppStore().toggleDevice('desktop')
  }
})

function handleClickOutside() {
  useAppStore().closeSideBar({ withoutAnimation: false })
}

const settingRef = ref(null);
function setLayout() {
  settingRef.value.openSetting();
}
</script>
注意:css部分没有粘贴到此处

可以看到在

template

部分,基本上是把定义的组件进行使用,这个地方可以理解为剪纸画,这个index就是一个画板,这些组件就像裁剪好的各种形状,在这个画布的对应位置粘贴上对应的形状,就组成了我们想要的作品。当然这个位置可以通过css来自己定义。

然后是

script

部分,这个部分先来看一下有什么东西,首先是导入,这里主要导入的是组件还有pinia状态管理工具。然后是一些

computed

计算属性,这里要想一下计算属性和普通函数的区别。接下来就是侦听器,这里有两种

watch

watchEffect

这里就要想一下他们的区别。最后就是一些函数,用来完成一些功能。

接下来就来一点一点的看一下这index到底做了什么?

首先是

template

部分,最外层是一个大的

div

盒子,包裹了所有的组件,把这个

div

盒子单独拎出来看一下

<div :class="classObj" class="app-wrapper" :style="{ '--current-color': theme }">
    组件内容
</div>

注意这个

:class

想一下这是vue当中的哪一个指令的简写

:class="classObj"

这个就是动态设置这个

div

的样式,它的值是

classObj

,这个东西是在

script

当中定义的一个计算属性,代码如下

const classObj = computed(() => ({
  hideSidebar: !sidebar.value.opened,
  openSidebar: sidebar.value.opened,
  withoutAnimation: sidebar.value.withoutAnimation,
  mobile: device.value === 'mobile'
}))

可以看到

classObj

返回的是一个对象,**这里要想一下当

:class

后面的值为数组和为对象的时候有什么区别**。那么这个对象当中的四对键值对是干嘛的?见名知意

hideSidebar

侧边栏隐藏,

openSidebar

侧边栏开启,

withoutAnimation

控制侧边栏开启关闭动画,

mobile

当前页面显示的设备,是移动设备还是桌面设备,注意移动设备和桌面设备在布局样式上有一些差异。

后面就是一个简单的

class="app-wrapper"

这个样式就是在当前的文件中进行定义的css样式,最后就是一个

:style="{ '--current-color': theme }

这里就是设置了一下主题颜色,设置了一个css变量。这样最外层的

div

盒子就看完了。

接下来是一个

div

自结束标签,如下

<div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside" />

它没有包裹任何东西,那么它的作用是什么呢?来分析,首先看到

v-if

这里想一下v-if和v-show的区别

v-if

后面的值为

true

它就显示,如果为

false

他就不显示。他其实就是移动端打开侧边时显示一个透明的黑色遮罩层。他有一个点击事件

@click="handleClickOutside"

这个点击事件就是点击遮罩层的时候,关闭侧边栏。

来解读一下它,就是当设备为移动端并且侧边栏打开的时候,就显示这个遮罩层,定义了他的样式,比如背景为黑色,有点透明度,给他一个点击事件,点击的时候关闭侧边栏。

后面就是自定义的组件,

sidebar

侧边栏组件

<sidebar v-if="!sidebar.hide" class="sidebar-container" />

首先是

v-if="!sidebar.hide"

,注意这里的

sidebar

不是组件,是定义的计算属性,作用是用于控制侧边栏的显示和隐藏,计算属性

sidebar

使用通过状态管理

pinia

获取的。

class="sidebar-container"

它是用来定义侧边栏的样式,注意这个

sidebar-container

样式类名不在当前的

index

文件当中,而是在

src/assets/style/sidebar.scss

文件中,这个文件在同目录下的

index.scss

文件中进行了导入,而

index.scss

又在

main.js

中进行了导入。

接着往下又是一个

div

盒子,这个盒子就包含了顶部导航栏、主体显示区域、侧边布局设置抽屉。

    <div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide }" class="main-container">
      <div :class="{ 'fixed-header': fixedHeader }">
        <!-- 顶部导航 -->
        <navbar @setLayout="setLayout" />
        <!-- 标签页 -->
        <tags-view v-if="needTagsView" />
      </div>
      <app-main />
      <settings ref="settingRef" />
    </div>

最外层的

div

同样是使用

:class

进行动态样式设置,

hasTagsView

是控制

.app-main

这个容器的最小高度,一般是顶部导航栏高度加上标签栏的高度,可以在

AppMain.vue

找到这个类。

sidebarHide

就是控制侧边栏隐藏的时候,当前容器的宽度。

再往下又是一个

div

容器还是使用

:class

动态的设置样式,这个容器放的是顶部导航栏以及标签栏,通过这个类名

fixed-header

就可以看出,这个样式的作用就是控制顶部导航栏是否需要固定。什么意思呢?就是当页面的高度超出视口的高度时,会出现滚动条,向下滚动时,如果顶部导航栏是固定的话,那么导航栏就不会向上滚动不见,说白点就是他固定之后,不管怎么滚动他都不会消失。

这个容器里面包裹了

navbar

tags-view

两个组件,

navbar

组件有一个自定义事件

@setLayout

,当事件触发时,调用

setLayout

函数,如下

const settingRef =ref(null);functionsetLayout(){  
  settingRef.value.openSetting();}

它的作用就是,当

navbar

内部触发了这个事件的时候,调用

setLayout

函数,这个函数的功能就是打开右侧设置布局的抽屉。

tags-view

组件它只有一个

v-if

用来控制它是否显示隐藏。

再往下就是

app-main

组件,他就是路由的出口,也就是后面增加一下路由,每一个路由都有对应的页面,选择对应的路由显示对应的页面,就是通过

app-main

来显示,后面会详细说这个组件。

最后就是

settings

组件,这个组件就是右侧的布局设置组件,他有一个

ref

属性,如下

<settings ref="settingRef" />

有了这个

ref

属性,就可以通过

settingRef

来调用这个组件当中的实例。就比如说上面的

setLayout

,就是通过这个

ref

属性,调用了

settings

组件当中的

openSetting()

方法。

以上就是index这个文件的基本组成,可以发现这个文件中计算属性都是从状态管理工具pinia中获取的,大部分都是与布局样式相关的,这是因为,若依这个前端它可以让用户进行页面布局的自定义,就是在不改代码的情况下,用户可以自定义更改颜色,布局等,那么就可以把这些值放在pinia中进行统一管理,在调用的时候会更加方便。

有分析不对的地方或者不足的地方,还请各位大佬在评论区指出多谢多谢


本文转载自: https://blog.csdn.net/weixin_45992725/article/details/143510243
版权归原作者 王赤脚 所有, 如有侵权,请联系我们删除。

“【若依】若依Vue3前端拆解分析--布局分析--index篇”的评论:

还没有评论