Vue3造轮子:使用Vite搭建官网

339 阅读3分钟

创建项目

打开命令行,进入学习目录

使用cmd/git bash/Terminal进入一个学习用的目录

cd /d/yang/jirengu

全局安装create-vite-app

yarn global add create-vite-app@1.18.0
或者
npm i -g create-vite-app@1.18.0

创建项目目录

cva <project-name>
或者
create-vite-app <project-name>

小知识:

  • vite文档给出的命令是
npm init vite-app <project-name>
yarn create vite-app <project-name>
  • 等价于
全局安装 create-vite-app 然后
cva <project-name>
  • 等价于
npx create-vite-app <project-name>
即 npx 会帮你全局安装用到的包

然后用VSCode打开目录

小知识

Vue2和Vue3的区别

  • 90%的写法完全一致,除了以下几点

  • Vue3的 Template 支持多个根标签,Vue2不支持

  • Vue3有createAPP(),而Vue2的是new Vue()

  • createApp(组件)new Vue({template, render})

引入 Vue Router 4(路由器,用于页面切换)

使用命令行查看 vue-router 所有版本号

npm info vue-router versions

安装 vue-router

yarn add vue-router@4.0.0-beta.3

初始化 vue-router

  • 新建history对象

  • 新建router对象

  • 引入Typescript

  • app.use(router)

  • 添加 < router-view >

  • 添加 < touter-link >

image.png

main.ts

import { createApp } from "vue";
import App from "./App.vue";
import "./index.css";
import { createWebHashHistory, createRouter } from "vue-router"; 
// 引入history对象和新建router对象
import Lily from "./components/Lily.vue";
import Lily2 from "./components/Lily2.vue";

const history = createWebHashHistory();  
//新建history对象
const router = createRouter({
  history,
  routes: [
    { path: "/", component: Lily },
    { path: "/xxx", component: Lily2 },
  ],
});
//新建router对象

const app = createApp(App);
app.use(router);
app.mount("#app");
// 使用app.use(router)

App.vue

<template>
  <div>
    导航栏 | <router-link to="/">Lily</router-link> |
    <router-link to="/xxx">Lily2</router-link>
  </div>
  <hr />
  <router-view />
</template>

<script>
export default {
  name: "App",
};
</script>

由于将main.js改成了main.ts,会出现报错: 找不到模块 xxx.vue

  • 出现原因: TypeScript只能理解 .ts文件,无法理解 .vue文件

  • 解决办法:搜索Vue3 can not find module,出现下面的解决方法

在src目录里面创建一个shims-vue.d.ts文件,内容为:

declare module "*.vue" {
  import { ComponentOptions } from "vue";
  const componentOptions: ComponentOptions;
  export default componentOptions;
}

创建首页和文档页

开始创建官网

Home.vue

  • Topnav: 左边是 logo ,右边是 menu

  • Banner: 文字介绍 + 开始按钮

Doc.vue

  • Topnav: 同上

  • Content:左边是 aside,右边是 main

新的路由

image.png

路径为 #/ 时

  • 渲染 Home.vue

路径为 #/doc 时

  • 渲染 Doc.vue

当写< style lang="scss" >时会出现下面的报错

image.png

解决方法:安装sass,yarn add sass@1.26.10

但是,加完sass之后,又报了一个错:

image.png

解决方法:将dependencies中的"sass": "1.26.10",移到devDependencies

image.png

Home 页面有一个topnav,Doc页面也有一个topnav,将他们封装成一个组件Topnav。

封装Topnav

<template>
  <div class="topnav">
    <div class="logo">LOGO</div>
    <ul class="menu">
      <li>菜单1</li>
      <li>菜单2</li>
    </ul>
  </div>
</template>
<script lang="ts">
export default {};
</script>

Home.vueDoc.vue< template >里面引入<Topnav/>,另外在<script>里面引入

Home.vue 和 Doc.vue

<script lang="ts">
import Topnav from "../components/Topnav.vue";
export default {
  components: { Topnav },
};
</script>

用provide和inject实现切换功能

完善Home的样式(h1+h2+两个链接)

<template>
  <div>
    <Topnav />
    <div class="banner">
      <h1>circle UI</h1>
      <h2>一个厉害的 UI 框架</h2>
      <p class="actions">
        <a href="https://github.com">GitHub</a>
        <router-link to="/doc">开始</router-link>
      </p>
    </div>
  </div>
</template> 

完善Doc样式 (边栏和主内容)

先实现手机,再实现PC

在aside里添加router-link(方便用户切换组件)

<template>
  <div class="layout">
    <Topnav class="nav" />
    <div class="content">
      <aside v-if="menuVisible">
        <h2>组件列表</h2>
        <ol>
          <li>
            <router-link to="/doc/switch">Switch 组件</router-link>
          </li>
          <li>
            <router-link to="/doc/button">Button 组件</router-link>
          </li>
          <li>
            <router-link to="/doc/dialog">Dialog 组件</router-link>
          </li>
          <li>
            <router-link to="/doc/tabs">Tabs 组件</router-link>
          </li>
        </ol>
      </aside>
      <main>
        <router-view />
      </main>
    </div>
  </div>
</template>

点击切换aside

点一次显示,再点一次隐藏,需要用到provide/inject

provide/inject

image.png

目标:点击button时,侧边栏显示,再次点击时,侧边栏收起来

需要用到一个变量:asideVisible,当侧边栏显示的时候,asideVisible = true,当侧边栏收起来的时候,asideVisible = false

分析后得知,这个变量只能放在APP里面,如何让Topnav和aside访问到APP里面的变量?只需要让APP标记一下这个asideVisible是可以被它的子组件访问的。

用什么标记呢?用provide

怎么获得这个标记呢?在子组件里使用inject()

App.vue

<template>
  <router-view />
</template>

<script lang="ts">
import { provide, ref } from "vue";
import { router } from "./router";

export default {
  name: "App",
  setup() {
    const width = document.documentElement.clientWidth;
    const asideVisible = ref(width <= 500 ? false : true);
    provide("asideVisible", asideVisible); // set
    router.afterEach(() => {
      if (width <= 500) {
        asideVisible.value = false; //当router切换时,如果宽度<=500,就显示为false侧边栏收回
      }
    });
  },
};

Topnav.vue

<template>
  <div class="topnav">
    <div class="logo" @click="toggleMenu">LOGO</div>
    <ul class="menu">
      <li>菜单1</li>
      <li>菜单2</li>
    </ul>
    <span class="toggleAside" @click="toggleMenu"></span>
  </div>
</template>
<script lang="ts">
import { inject, Ref } from "vue";
export default {
  setup() {
    const asideVisible = inject<Ref<boolean>>("asideVisible"); //get
    const toggleMenu = () => {
      asideVisible.value = !asideVisible.value; //asideVisible的值取反
    };
    return { toggleMenu };
  },
};
</script>

Doc.vue

<template>
  <div class="layout">
    <Topnav class="nav" />
    <div class="content">
      <aside v-if="asideVisible"> 
        <h2>组件列表</h2>
        <ol>
          <li>
            <router-link to="/doc/switch">Switch 组件</router-link>
          </li>
          <li>
            <router-link to="/doc/button">Button 组件</router-link>
          </li>
          <li>
            <router-link to="/doc/dialog">Dialog 组件</router-link>
          </li>
          <li>
            <router-link to="/doc/tabs">Tabs 组件</router-link>
          </li>
        </ol>
      </aside>
      <main>
        <router-view />
      </main>
    </div>
  </div>
</template>
<script lang="ts">
import { inject, Ref } from "vue";
import Topnav from "../components/Topnav.vue";
export default {
  components: { Topnav },
  setup() {
    const asideVisible = inject<Ref<boolean>>("asideVisible");
    return { asideVisible };
  },
};
</script>

注意: 必须标注asideVisible的类型为boolean

手机页面上的切换按钮:改造topnav(添加一个切换按钮)

image.png

通过获取页面的宽度,来确定我的初始值是true还是false

image.png

路由间切换(嵌套路由)

新建一个router.ts文件

import { createWebHashHistory, createRouter } from "vue-router";
import Home from "./views/Home.vue";
import Doc from "./views/Doc.vue";
import SwitchDemo from "./components/SwitchDemo.vue";
import ButtonDemo from "./components/ButtonDemo.vue";
import DialogDemo from "./components/DialogDemo.vue";
import TabsDemo from "./components/TabsDemo.vue";
import DocDemo from "./components/DocDemo.vue";

const history = createWebHashHistory();
export const router = createRouter({
  history: history,
  routes: [
    { path: "/", component: Home },
    {
      path: "/doc",
      component: Doc,
      children: [
        { path: "", component: DocDemo },
        { path: "switch", component: SwitchDemo },
        { path: "button", component: ButtonDemo },
        { path: "dialog", component: DialogDemo },
        { path: "tabs", component: TabsDemo },
      ],
    },
  ],
});
router.afterEach(() => {
  console.log("路由切换了");
});

image.png