创建项目
打开命令行,进入学习目录
使用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 >
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
新的路由
路径为 #/ 时
- 渲染
Home.vue
路径为 #/doc 时
- 渲染
Doc.vue
当写< style lang="scss" >时会出现下面的报错
解决方法:安装sass,yarn add sass@1.26.10
但是,加完sass之后,又报了一个错:
解决方法:将dependencies中的"sass": "1.26.10",移到devDependencies中
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.vue 和 Doc.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
目标:点击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(添加一个切换按钮)
通过获取页面的宽度,来确定我的初始值是true还是false
路由间切换(嵌套路由)
新建一个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("路由切换了");
});