Important
本库功能仍有部分功能未完成文档尚未完成。
This library has some features that are not finished yet.
后续将提供机器翻译的英文版。
A machine-translated English version will be provided later.
Bar component for framing main content in Nuogz Web App, based on Vue 3.
框住主内容的边栏组件。用于Nuogz Web App,基于Vue3、UnoCSS、Vue Router
环绕应用,也就是常见的侧/顶/底栏。四侧内容围着主内容,形似环绕天体。因而得名天轨。
经过一系列的迭代,从原来的侧栏组件vue-sidebar升级重构为全新的web-app-orbit
基础示例:
<AppOrbit mode="block">
<!-- 顶栏slot -->
<template #top>
<span>Orbit Demo</span>
</template>
<!-- 左栏slot -->
<template #left>
<Navi v-for="menu of menus" @click="changeTo(menu)">
{{ menu.title }}
</Navi>
</template>
<!-- 主内容slot -->
<template #main>
<div>Hello Orbit!</div>
</template>
</AppOrbit>使用天轨组件,会导致DOM结构产生变化:
非none模式,主内容会被一层app-main元素包裹,app-moon元素为各种边栏:
- body
- app (index.vue)
- app-moon[dirn=top]
- app-moon[dirn=left]
- app-moon[dirn=side][side=left]
- app-main
- (module.vue)
- app-moon[dirn=side][side=right]
- app-moon[dirn=right]
- app-moon[dirn=bottom]
- app-orbit-state (用于css选择器状态检测)
- app (index.vue)
碎碎念1
orbit是围绕天体的轨道。moon是我们再熟悉不过的卫星——月亮。很好理解吧?虽然它在我的组件中可能会有四颗……
none模式,DOM结构与原来保持一致,相当于禁用该组件:
- body
- app (index.vue)
- (module.vue)
- app (index.vue)
指定组件以哪种形式实现边栏功能。默认是none无边栏模式
<AppOrbit mode="border">...</AppOrbit>none无边栏模式
直接插入<主内容>,没有额外元素border文档流模式
边栏不脱离文档流,通过明确的宽高计算使主界面保持四个边栏的中间。
支持圆角边缘(需指定背景颜色)。滚动条在<主内容>侧边
计划支持但是搁置中的模式:
fixed视口固定模式
边栏使用position: fixed脱离文档流,固定视口四侧中。主界面使用padding配合。
不支持圆角边缘。滚动条在视口侧边fixed-nowrap视口固定模式(无包裹)
边栏原理同视口固定模式,但<主内容>不使用app-main包裹,直接放置与app下
碎碎念2
本来视口固定模式开发得很顺利,但一加入边角的设计,复杂度直线上升加上就我一个人对多种模式的需求很低,就先完成`border`就算了
side侧栏可以让开发者无需关注侧栏的左右位置,方便交由由用户自行控制。默认是left侧栏在左
<AppOrbit side="left">...</AppOrbit>left侧栏在左right侧栏在右
当两个相邻的边栏同时生效时,两个边栏就会相交的边角产生重叠冲突。
corner就是为了解决由谁来使用边角而存在的
该属性会影响视口的四角由哪个边栏占用的。默认是x侧栏优先
支持数组、空格/逗号连接的字符串等多种定义形式
<AppOrbit corner="x">...</AppOrbit>y顶栏和Y轴优先x侧栏(左/右栏、X轴)优先l左栏优先r右栏优先
除预设值外,可以精确指定四角由谁占用,以顶栏、右栏为例,有以下三种传参方式:
{ 'top-left': 'top', 'bottom-left': 'left' } // 对象
// 左上角由顶栏占用,左下角由左栏占用
['top', 'right'] // 数组
// 左上角由顶栏占用,右上角由右栏占用
'top top' // 字符串
// 左上角由顶栏占用,右上角由顶栏占用数组、空格/逗号连接的字符串类型参数的键值顺序是:
top-left左上top-right右上bottom-left左下bottom-right右下
支持数组、空格/逗号连接的字符串等多种定义形式
<AppOrbit hide="top right">...</AppOrbit>// 以下均为隐藏顶栏、右栏
{ top: true, right: true } // 对象
['top', 'right'] // 数组
'top right' // 字符串top上right右bottom下left左side侧all全
组件除了导出组件本身外,还导出是一个名为$state的Ref引用,方便用户侦听组件状态
import { $state } from '@nuogz/web-app-orbit';
console.log($state.value.mode);
// 'block' ==> block模式
console.log($state.value.side);
// 'left' ==> 侧栏在左
console.log($stateOrbit.corner['top-left']);
// 'top' ==> 左上角被顶栏占用
console.log($stateOrbit.corner.top);
// ['left', 'right'] ==> 顶栏占用了左上角与右上角
console.log($state.value.moonsShowed);
// ['top', 'side'] ==> 当前显示顶栏和侧栏
console.log($state.value.dirnsShowed);
// ['top', 'left'] ==> 当前<主内容>的上侧和左侧有边栏在显示moonsShowed表达哪个边栏在显示
dirnsShowed表达哪个方位有边栏在显示
可通过覆盖一系列渐进的css变量,以达到控制边栏的外观
--app-orbit-back
边栏背景色
默认值var(--main-solid)--app-orbit-back-text
边栏字体色
默认值var(--contrast)--app-orbit-back
主内容背景色
默认值var(--main-back)
关于默认的颜色,请参阅NWA的主题颜色部分(仍未完成)
尺寸边栏渐进的,表示范围越小的变量优先级越高
top/bottom/left/right/side是最终汇算应用的变量,
表示四侧边栏的宽度,默认值是0。
一般不推荐修改最终变量。
t/l/r/b/x/y/a分别表示上/左/右/下/横轴/竖轴/全部的精确变量。
均无默认值。推荐优先设置这些变量以保证优先级有效
side由于左右通用,因此x横轴变量优先级会比l/r左右两侧变量高
--app-orbit-top上var(--app-orbit-t)var(--app-orbit-y)var(--app-orbit-a)0
--app-orbit-left左var(--app-orbit-l)var(--app-orbit-x)var(--app-orbit-a)0
--app-orbit-right右var(--app-orbit-r)var(--app-orbit-y)var(--app-orbit-a)0
--app-orbit-bottom下var(--app-orbit-b)var(--app-orbit-y)var(--app-orbit-a)0
--app-orbit-side侧var(--app-orbit-x)var(--app-orbit-left)var(--app-orbit-right)0
已知none模式与非none模式的dom结构并不一样,
包裹<主内容>的元素可能是<app>,也可能<app>下的<app-main>。
同时在多模块环境下,还存在另一个问题:模块加载后全局样式会进入文档流。
但是当模块切换时,旧模块的全局样式并不会跟着卸载。
为了简化选择父主元素,综合上述问题,利用侦听mode与vue-router的守卫函数进行了一些改造:
使得无论在哪个模式下,包括<主内容>的父主元素总是拥有属性id="app"和route="当前路由"(去除开头的/)。
用户可以根据这两个属性进行精确的元素选择,避免样式冲突
示例:
单文件全局样式
<style lang="sass">
#app[route="demo/current-route-path"]
@apply p-2 bg-blue-1
</style>局部样式通过:global提升到全局
<style lang="sass" scoped>
:global(#app[route="demo/current-route-path"])
@apply p-2 bg-blue-1
</style>如果是想只在用none模式或者明确只使用none模式
<style lang="sass">
app:not(:has(app-main))[route="demo/current-route-path"]
@apply p-2 bg-blue-1
</style>