前言
啰嗦几句哈,系列篇一
中的 Demo
项目不会作为正式的项目,在写那个Demo项目时,Vue3
还没有出来,在 Vue2.0
里面写 TypeScript
是比较麻烦的,但是通过 vue-class-component
写起来就还不错,虽然要去熟悉好多新的东西,增加了心理压力哈哈哈哈~~~
终于啊,Vue3
出来了,天然支持 TypeScript
,我们再也不用增加那么多心智负担了,废话就不说了,直接撸起袖子干。
环境依赖
- node v14.15.1
- npm 7.7.2
- qiankun ^2.4.1
- @vue/cli 4.5.11
- Vue3 ^3.0.0
- Typescript ~3.9.3
- ant-design-vue ^2.0.0
- vue-router ^4.0.4
- vuex 4.0
初始化项目
通过 vue create project-name
创建项目
选择 Manually select features
选择 TypeScript
,选择 3.x (Preview)
在初始化项目的时候,最好是安装 vue-router
和 vuex
,因为这也是我们项目中必须要的依赖,否则我们在写的过程中还需要手动去添加!
选择 ESLint + Standard config
,Lint on save
,
选择In dedicated config files
,在专用配置文件中配置各自的信息
选择 Save this as a preset for future projects?
Yes
,将配置保存为未来项目的预设,将来创建项目就可以直接选择你的模板了。
最后回车,静静的等待就好了。
具体配置如图所示:
项目初始化完成之后,打开项目看到如下目录结构:
然后我们随便改点东西试试:
到此我们的 Vue3
+ TypeScript
项目就创建好了。
ant-design-vue 2.0
安装
npm install ant-design-vue@^2.0.0 -S
yarn add ant-design-vue@^2.0.0 -S
按需引入
安装 babel-plugin-import
插件
修改 babel.config.js
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
],
plugins: [
[
"import",
{ libraryName: 'ant-design-vue', libraryDirectory: "es", style: true }
]
]
}
如何使用this.$message
- 方法一: 使用
provide/inject
(用于组合或选项API)
import { message } from 'ant-design-vue'
const app = createApp({ ... })
app.provide('message', message)
在组件中使用
import { inject } from 'vue'
setup() {
const $message = inject('message')
$message.success('Hello_AlexCc')
}
- 方法二: 使用全局配置
globalProperties
注意:这只适用于选项API。
import { message } from 'ant-design-vue'
const app = createApp({ ... })
app.config.globalProperties.$message = message
在组件中使用
mounted() {
this.$message.success('mounted: this.$message.success')
}
或者
<a-button @click="$message.error('error!!')">弹窗</a-button>
使用ant图标
当你复制一个图标粘贴到代码里去,它是一个组件,比如 问号
图标 <QuestionOutlined />
。
你需要从 @ant-design/icons-vue
中导入。
如果没有安装的话,需要 yarn add @ant-design/icons-vue
使用 iconfont 图标
iconfont官网
首先我们去到 iconfont
官网,找一些你喜欢的图标,将他们收藏到你自己的仓库。
import { StepForwardOutlined, createFromIconfontCN } from '@ant-design/icons-vue'
// 使用 iconfont 图标,这里的 url 就是你收藏的 iconfont 项目 js 路径
const IconFont = createFromIconfontCN({
scriptUrl: '//at.alicdn.com/t/font_2299454_fvw4ct8o61.js'
})
// 局部注册 IconFont
components: { IconFont }
// 全局注册
export default {
// App 是 vue实例 的类型
install: (app: App, options: InstallOptions = defaultInstallOpt ) => {
app.component('icon-font', IconFont)
AntdComponent.forEach(comp => {
app.component(comp.name, comp)
})
}
}
使用图标
<div class="icon-list">
<icon-font type="icon-mugua"></icon-font>
<icon-font type="icon-caomei"></icon-font>
<icon-font type="icon-xigua"></icon-font>
<icon-font type="icon-yingtao"></icon-font>
<icon-font type="icon-douya"></icon-font>
<icon-font type="icon-xianggu"></icon-font>
<icon-font type="icon-angel"></icon-font>
</div>
<style scoped lang="less">
.icon-list {
padding: 2em 0;
:deep(.anticon) {
font-size: 36px;
margin-right: .5em;
}
}
</style>
效果如下。
vue-router 4
- 官网地址
安装
使用npm 或者 yarn
npm install vue-router@4 -S
yarn add vue-router@4 -S
使用
createRouter
函数可以创建一个被 Vue
应用程序使用的实例。Options
用来初始化 router
。
createWebHistory
创建一个HTML5
历史,单页面应用程序中最常见的历史记录。也就是之前版本的 mode
: history
。 另一种常见的 hash
模式,在 v4
中采用 createWebHashHistory
。路由表中的用法还是跟以前一样用就行了。
// router/index.ts
export default createRouter({
history: createWebHistory(),
routes: constantRoutes
})
不过,在 composition api
中我们都是通过 setup
钩子作为组合式API
的入口,里面是无法使用 this
的,不过在 template
中可以使用 $router
或者 $route
。
那么我们如何像之前那样通过编程式路由 this.$router
或者 this.$route
呢?
使用 useRouter
和 uesRoute
import { useRouter, useroute } from 'vue-router'
setup() {
const router = useRouter()
const store = useStore()
router.push('/login')
}
其它 Router Api
去官网查看就好了。
Vuex 4.0
- 官网地址
安装
使用 npm 或者 yarn 安装
npm install vuex@next --save
yarn add vuex@next --save
使用
创建 store/index.ts
文件,从 vuex
中导入 createStore
来创建我们的 store
实例,写好内容后不要忘了使用 vue
去注册。
// store/index.ts
import { createStore } from "vuex"
// 定义存储状态的类型
export interface State {
count: number
}
// 如果不将 'State' 接口传入到 'createStore' 中,在 'mutations' 中使用的 state 会被推测为 'unknown' 类型
const store = createStore<State>({
state() {
return {
count: 0
}
},
mutations: {
increment(state) {
state.count++
}
}
})
export default store
注册store
// main.ts
const app = createApp({ /* your root component */ })
app.use(store)
当我们需要用 在 store
中定义的 count
时,发现 count
的类型是 any
当我们在Composition API中编写Vue组件时,很可能希望useStore
返回类型化的存储。为了让useStore
正确地返回输入的存储,必须做如下几步操作:
1. 定义类型化的`InjectionKey`。
2. 在`Vue`应用程序中安装 `store` 时提供类型化的`InjectionKey`。
3. 将类型化的`InjectionKey`传递给`useStore`方法。
回到 store/index.ts
文件
```ts
import { InjectionKey } from "vue"
import { createStore, Store } from "vuex"
// 定义注入 key
export const key: InjectionKey<Store<State>> = Symbol()
```
然后我们可以将key
传递给useStore
方法以检索类型化的存储,在使用的地方就能正确推到出state.count
的类型了。
qiankun
在 系列一
文中已经介绍 qiankun
和 微前端
的概念了,这里就不再啰嗦了。
安装
yarn add qiankun@2.4.1 -S
使用
虽然 系列篇一 中已经写过用法了,但是在正式开始的这个项目里面还是有点不一样,所以这里我们再看看如何再 Vue3
中使用它。
现在我们还是以一个小栗子为入口,去了解如何使用它。
首先我们在 src
下面新建一个文件 single-spa.ts
文件,用来处理连接 子应用
的配置,代码很简单,直接上代码,里面描述了一些关键信息。
//single-spa.ts
import {
registerMicroApps,
setDefaultMountApp,
addGlobalUncaughtErrorHandler,
start
} from "qiankun"
const apps = [
{
name: 'vue3-base', // 应用名称
entry: '//localhost:8080', // 应用入口,资源路径
container: '#subAppContainer', // 在主体中存放 子应用 的容器 id
activeRule: '/vue-base', // 根据此规则切换指定子应用,激活规则
props: {
// 传递给子应用的数据
user: {
name: 'ZHONG TAI ADMIN',
age: 18
}
}
}
]
const excutorSingleSpa = () => {
registerMicroApps(apps, {
beforeLoad: [
// @ts-ignore
app => {
console.log('加载应用之前打印apps', app)
}
]
})
addGlobalUncaughtErrorHandler((event: Event | string) => {
console.error(event)
const { message: msg } = event as any
// 加载失败时提示
if (msg || msg.includes("died in status LOADING_SOURCE_CODE")) {
console.error("微应用加载失败,请检查应用是否可运行", msg);
}
})
start({
// 是否开启预加载,默认为 true。
// 配置为 true 则会在第一个微应用 mount 完成后开始预加载其他微应用的静态资源
prefetch: false,
sandbox: true
})
}
export default excutorSingleSpa
在项目结构方面,我们一般都会有一个 layouts.vue
组件,里面有个一区域是用来渲染我们各个路由页面的。而我们的 子应用
也是在这里渲染的。
// layout/index.vue
// 其它结构省略
<a-layout-content
:style="{ background: '#fff', padding: '24px', margin: 0, minHeight: '280px' }">
<!-- 主内容渲染部分 -->
<router-view></router-view>
<!-- 子应用渲染部分 -->
<div id="subAppContainer"></div>
</a-layout-content>
在 layout/index.vue
文件中,我们引入 single-spa.ts
文件。
import useSingleSpa from '@/single-spa'
setup() {
useSingleSpa()
}
然后我们在 router/index.ts
中,加入 子应用
的菜单。
// routes
import { RouterView } from 'vue-router'
const routes = [
// 省略其它路由
{
path: '/vue-base',
component: Layout,
children: [
{
path: 'home',
// `RouterView` 表示显示当前路由,就跟 `<router-view />` 一样。
// 以前我们可能是这么写 component: h => h('router-view')
component: RouterView,
},
{
path: 'about',
component: RouterView,
}
]
}
]
到这里,主项目就差不多配置好了。然后去配置 子应用
。
子应用配置
如果你看了 系列篇一
,就知道我们在子应用中不需要安装任何依赖,只需要在 main.ts
中导出这几个钩子函数 bootstrap
,mount
,unmount
。
我们看下子应用的路由如何配置。
这里的根目录 '/'
是相对于子应用的,由于通过createWebHistory('/vue-base')
设置了路由前缀,其实这里会是 /vue-base
,然后重定向到 /vue-base/about
// router/index.ts
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
import Home from '../views/Home.vue'
const routes: Array<RouteRecordRaw> = [
{
path: '/',
redirect: '/about'
},
{
path: '/home',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// 路由懒加载
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
const router = createRouter({
// 检测如何是由主体渲染的,就加个 `/vue-base` 路由前缀,以便区分主体和子应用的路由
history: window.__POWERED_BY_QIANKUN__ ? createWebHistory('/vue-base') : createWebHistory(process.env.BASE_URL),
routes
})
export default router
子应用的 App.vue
的结构如下
<template>
<div class="app">
<div id="nav">
<router-link to="/home">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<!-- 渲染匹配的路由component -->
<router-view></router-view>
</div>
</template>
然后我们创建 vue.config.js
,来处理 子应用
嵌入主体项目可能会出现的问题。
const { name } = require('./package.json')
module.exports = {
devServer: {
headers: {
"Access-Control-Allow-Origin": "*"
}
},
configureWebpack: {
output: {
library: `${name}-[name]`,
libraryTarget: 'umd',
jsonpFunction: `webpackJsonp_${name}`
}
}
}
到这里,我们的子应用 vue-base
就配置好了。
我们来看下效果吧!
现在看到的界面是 主体
项目的首页。
这个界面,就是点击 导航vue-base
之后看到的页面。
到这里,我们的子应用和主体就链接起来了,之后项目不停的迭代之后,会变得越来越复杂。
一起交流
如果喜欢这部分内容,就加入我们的QQ群,和大家一起交流技术吧~
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!