前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >学习 Vue 3 全家桶 - 打造自己的通用组件库 - 环境搭建

学习 Vue 3 全家桶 - 打造自己的通用组件库 - 环境搭建

作者头像
Cellinlab
发布2023-05-17 16:56:52
2360
发布2023-05-17 16:56:52
举报
文章被收录于专栏:Cellinlab's BlogCellinlab's Blog

# 环境搭建

# 创建 vite 项目

代码语言:javascript
复制
npm init vite@latest

# √ Project name: ... cellinlab-ui
# √ Select a framework: » vue
# √ Select a variant: » vue-ts
# Done. Now run:
#   cd cellinlab-ui
#   npm install
#   npm run dev

# Sass

在项目里集成 CSS 预编译器,可以更快、更高效地管理和编写 CSS 代码。

代码语言:javascript
复制
npm install -D sass

# ESLint

代码语言:javascript
复制
npm install -D eslint

ESLint 配置初始化

代码语言:javascript
复制
$ npx eslint --init

可以在 .eslintrc.json 中修改配置

代码语言:javascript
复制
{
    "env": {
        "browser": true,
        "es2021": true
    },
    "extends": [
        "eslint:recommended",
        "plugin:vue/essential",
        "plugin:@typescript-eslint/recommended"
    ],
    "parserOptions": {
        "ecmaVersion": "latest",
        "parser": "@typescript-eslint/parser",
        "sourceType": "module"
    },
    "plugins": [
        "vue",
        "@typescript-eslint"
    ],
    "rules": {
    }
}

运行 ESLint 检查

代码语言:javascript
复制
npx eslint src

# husky

安装和初始化 husky

代码语言:javascript
复制
npm install -D husky

npx husky install # 初始化 husky

新增 commit-msg 钩子,来校验 commit 信息格式

代码语言:javascript
复制
npx husky add .husky/commit-msg "node scripts/commit-msg.js"

scripts/commit-msg.js

代码语言:javascript
复制
const msg = require('fs')
  .readFileSync('.git/COMMIT_EDITMSG', 'utf-8')
  .trim();

const commitRE = /^(revert: )?(feat|fix|docs|dx|style|refactor|perf|test|workflow|build|ci|chore|types|wip|release)(\(.+\))?: .{1,50}/;
const mergeRe = /^(Merge pull request|Merge branch)/;
if (!commitRE.test(msg)) {
  if(!mergeRe.test(msg)){
    console.log('git commit信息校验不通过');
    console.error(`git commit的信息格式不对, 需要使用 title(scope): desc的格式
      比如 fix: xxbug
      feat(test): add new 
      具体校验逻辑看 scripts/verifyCommit.js
    `);
    process.exit(1);
  }
}else{
  console.log('git commit信息校验通过');
}

# 布局容器

# 需求拆分

参考 Element3 布局容器页面,共有 container、header、footer、aside、main 五个组件,这个组合可以很方便地实现常见的页面布局:

  • <cell-container> 组件负责外层容器
    • 当子元素中包含 <cell-header><cell-footer> 时,全部子元素会垂直上下排列,否则会水平左右排列
  • <cell-header> 组件负责头部
  • <cell-aside> 组件负责侧边栏
  • <cell-main> 组件负责主体内容
  • <cell-footer> 组件负责底部

# 组件实现

组件中所有样式需要加上 cell- 前缀,可以使用 Sass 的 Mixin 来实现。

新建 src/components/styles/mixin.scss,添加如下内容:

代码语言:javascript
复制
// 定义变量
$namespace: 'cell';
$state-prefix: 'is-';

// 使用 mixin 注册模块 b
@mixin b($block) {
  // 通过 传入的 $block 生成一个新的变量 $B
  $B: $namespace + '-' + $block !global; // !global 表明该变量是全局的
  .#{$B} {
    // @content 占位,@include 传入相应内容
    @content;
  }
}

@mixin when($state) {
  @at-root {
    &.#{$state-prefix + $state} {
      @content;
    }
  }
}

src/components/container/Container.vue 中添加如下内容:

代码语言:javascript
复制
<template>
  <section
    class="cell-container"
    :class="{ 'is-vertical': isVertical }"
  >
    <slot/>
  </section>
</template>
<script lang="ts">
export default {
  name: 'CellContainer',
}
</script>
<script setup lang="ts">
import { Component, computed, useSlots, VNode } from 'vue'
interface Props {
  direction?: string;
}
const props = defineProps<Props>();

const slots = useSlots();

const isVertical = computed(() => {
  if (slots && slots.default) {
    return slots.default().some((vn: VNode) => {
      const tag = (vn.type as Component).name;
      return tag === 'CellHeader' || tag === 'CellFooter';
    });
  } else {
    if (props.direction === 'vertical') {
      return true;
    } else {
      return false;
    }
  }
});
</script>
<style lang="scss" scoped>
@import '../syles/mixin';
@include b(container) {
  display: flex;
  flex-direction: row;
  flex: 1;
  flex-basis: auto;
  box-sizing: border-box;
  min-width: 0;
  @include when(vertical) {
    flex-direction: column;
  }
}
</style>

上述代码中,使用 b(container) 生成 cell-container 样式类,在内部使用 when(vertical) 生成 .cell-container.is-vertical 样式类以便修改 flex 布局方向。

container 组件内部如果没有 header 或 footer 组件,就是横向布局,否则就是垂直布局。

这里使用了两个 script 标签,是因为要确保每个组件有自己的名字,script setup 中不能返回组件的名字,所有需要单独的标签,使用 options 语法设置组件的 name 属性。

src/components/container/Header.vue 中添加如下内容:

代码语言:javascript
复制
<template>
  <header
    class="cell-header"
    :style="{ height }"
  >
    <slot/>
  </header>
</template>

<script lang="ts">
export default {
  name: 'CellHeader',
}
</script>

<script setup lang="ts">
import { withDefaults } from 'vue'

interface Props {
  height?: string;
}
withDefaults(defineProps<Props>(), {
  height: '60px',
});
</script>


<style lang="scss">
@import '../syles/mixin';
@include b(header) {
  padding: $--header-padding;
  box-sizing: border-box;
  flex-shrink: 0;
}
</style>

src/components/container/Aside.vue 中添加如下内容:

代码语言:javascript
复制
<template>
  <aside
    class="cell-aside"
    :style="{ width }"
  >
    <slot/>
  </aside>
</template>

<script lang="ts">
export default {
  name: 'CellAside',
}
</script>

<script setup lang="ts">
import { withDefaults } from 'vue';

type PropValues = {
  width: string;
};

withDefaults(defineProps<PropValues>(), {
  width: '300px',
});
</script>

<style lang="scss">
@import '../styles/mixin';
@include b(aside) {
  overflow: auto;
  box-sizing: border-box;
  flex-shrink: 0;
}
</style>

src/components/container/Footer.vue 中添加如下内容:

代码语言:javascript
复制
<template>
  <footer
    class="cell-footer"
    :style="{ height }"  
  >
    <slot/>
  </footer>
</template>

<script lang="ts">
export default {
  name: 'CellFooter',
}
</script>

<script setup lang="ts">
import { withDefaults } from 'vue';

interface Props {
  height?: string;
}

withDefaults(defineProps<Props>(), {
  height: '60px',
});
</script>

<style lang="scss">
@import '../syles/mixin';
@include b(footer) {
  padding: $--footer-padding;
  box-sizing: border-box;
  flex-shrink: 0;
}
</style>

src/components/container/Math.vue 中添加如下内容:

代码语言:javascript
复制
<template>
  <main class="cell-main">
    <slot/>
  </main>
</template>

<script lang="ts">
export default {
  name: 'CellMain',
}
</script>

<script setup lang="ts">

</script>

<style lang="scss">
@import '../styles/mixin';
@include b(main) {
  display: block;
  flex: 1;
  flex-basis: auto;
  overflow: auto;
  box-sizing: border-box;
  padding: $--main-padding;
}
</style>

# 组件注册

为了方便注册,这里使用插件机制对外暴露安装的接口,新建 scr/components/container/index.ts 文件,添加下面代码:

代码语言:javascript
复制
import { App } from 'vue';
import CellContainer from './Container.vue';
import CellHeader from './Header.vue';
import CellFooter from './Footer.vue';
import CellAside from './Aside.vue';
import CellMain from './Main.vue';

export default {
  install(app: App) {
    app.component(CellContainer.name, CellContainer);
    app.component(CellHeader.name, CellHeader);
    app.component(CellFooter.name, CellFooter);
    app.component(CellAside.name, CellAside);
    app.component(CellMain.name, CellMain);
  }
};

现在,就可以在 src/main.ts 中整体进行引入了:

代码语言:javascript
复制
import { createApp } from 'vue'
import App from './App.vue'

import CellContainer from './components/container'

const app = createApp(App)
app
  .use(CellContainer)
  .mount('#app')

# 组件使用

src/App.vue 中展示:

代码语言:javascript
复制
<template>
  <cell-container>
    <cell-header>Header</cell-header>
    <cell-main>Main</cell-main>
    <cell-footer>Footer</cell-footer>
  </cell-container>
  <hr>
  <cell-container>
    <cell-header>Header</cell-header>
    <cell-container>
      <cell-aside width="200px">Aside</cell-aside>
      <cell-main>Main</cell-main>
    </cell-container>
  </cell-container>
  <hr>
  <cell-container>
    <cell-aside width="200px">Aside</cell-aside>
    <cell-container>
      <cell-header>Header</cell-header>
      <cell-main>Main</cell-main>
      <cell-footer>Footer</cell-footer>
    </cell-container>
  </cell-container>
</template>

<script setup lang="ts">
</script>

<style>
body {
  width: 1000px;
  margin: 10px auto;
}
.cell-header,
.cell-footer {
  background-color: #b3c0d1;
  color: #333;
  text-align: center;
  line-height: 60px;
}
.cell-aside {
  background-color: #d3dce6;
  color: #333;
  text-align: center;
  line-height: 200px;
}
.cell-main {
  background-color: #e9eef3;
  color: #333;
  text-align: center;
  line-height: 160px;
}

body > .cell-container {
  margin-bottom: 40px;
}

.cell-container:nth-child(5) .cell-aside,
.cell-container:nth-child(6) .cell-aside {
  line-height: 260px;
}
.cell-container:nth-child(7) .cell-aside {
  line-height: 320px;
}
</style>
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022/2/14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • # 环境搭建
    • # 创建 vite 项目
      • # Sass
        • # ESLint
          • # husky
          • # 布局容器
            • # 需求拆分
              • # 组件实现
                • # 组件注册
                  • # 组件使用
                  相关产品与服务
                  容器服务
                  腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档