vue3 + vite + ts 从无到有 造轮子

一、创建项目

1
2
npm init vite-app <project>
npm install & npm run dev

安装VSCODE插件

Snippets

定义vue解析文件

1
2
3
4
5
6
// config.d.ts
declare module '*.vue' {
import {ComponentOptions} from 'vue'
const component : ComponentOptions
export default component
}

vue-router@4

yarn add vue-router@4.0.0-beta3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { createApp } from 'vue'
import App from './App.vue'
import '../assets/css/index.css'
import {createWebHashHistory,createRouter} from 'vue-router'
import Frank from '../components/Frank.vue'
const history = createWebHashHistory()
const router = createRouter({
history,
routes:[
{
path:'/',
component:Frank
}
]
})
const app = createApp(App)
app.use(router)
app.mount('#app')

sass

yarn add sass@1.26.10 -D

二、2和3的一些小知识

  • 90%的写法一致
  • 3支持template支持多个根标签 2不支持
  • 3有createApp(组件) 2是new Vue({template,render})
  • 新v-model代替以前的v-model 和.sync
  • 新增context.emit

三、组件轮子相关

通信 Provide Inject

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { ref, provide} from 'vue'
export default {
setup(){
const menu = ref(false)
provide('xxx',menu) // set
}
}

import {inject,Ref} from 'vue'
export default {
setup(){
const menu = inject<Ref<boolean>>('xxx') // get
console.log(menu)
}
}

通信$event 和 context.emit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//父
<Switch :value="y" v-model:value="y"></Switch>

//子
props: {
value: Boolean
},
setup(props,context) {// 初始化
const toggle = () =>{
// 重点vue3改变 update:value
context.emit('update:value',!props.value)
}
return {toggle}
}

使用REF创建内部数据

1
2
3
4
5
6
7
import {ref} from 'vue'
export default {
setup(){
const menu = ref(false)
console.log(menu)
}
}

四、属性绑定

  • 默认属性都绑定到根元素
  • 使用inheritAttrs:false可取消默认绑定
  • 使用$attrs或者 context.attrs获取所有属性
  • 使用v-bind=“$attr”批量绑定属性
  • 使用const {size,…rest} = context.attrs 将属性分开

props vs attrs

  • props要先声明才能取值,attrs不用
  • props不包含事件,attrs包含
  • props支持string以外的类型,attrs只有string类型

可以将proxy转对象来打印 console.log({…props})

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
<div :size="size">
<button v-bind="rest">
<slot />
</button>
</div>
</template>
<script lang="ts">
export default {
inheritAttrs:false,
setup(props,context){
const {size,...rest} = context.attrs
return {size,rest}
}
}
</script>

库 CSS 的两个注意事项

  • 不能使用scoped
    • 因为data-v-xxx中xx每次不同
    • 必须输出稳定不变的class选择器,方便使用者覆盖
  • 必须加前缀
    • .button .gulu-button 前者更容易比后者被使用者覆盖
    • .theme-link .gulu-theme-link 前者更容易比后者被使用者覆盖

CSS最小影响原则

1
2
3
4
[class^="gulu-"],[class*=" gulu-"]{
// ^= 属性以什么开着 第二个第三个值*=含有
margin:0;padding:0;box-sizing:border-box;
}

组件的小思路

1
2
3
4
5
6
7
8
9
10
<Button
@click="onClick"
@focus="onClick"
@mouseover="onClick"
size="small normal big"
theme="button link text"
level="main normal minor"
disabled
loading
/>

五、插槽

1
<template v-slot:header></template>

六、Teleport

Teleport(以前称为Portal)是将子节点渲染到DOM谱系之外的DOM节点中的安全通道,例如弹出窗口甚至是模式。在此之前,使用CSS通常会遇到很多麻烦,现在Vue允许您使用在模板部分中进行处理。

1
2
3
4
5
6
7
8
9
10
11
12
<teleport to="#modals">
<div>A</div>
</teleport>
<teleport to="#modals">
<div>B</div>
</teleport>

<!-- result-->
<div id="modals">
<div>A</div>
<div>B</div>
</div>

七、Suspense

1
2
3
4
5
6
7
8
<Suspense>
<template>
<Suspended-component />
</template>
<template #fallback>
Loading...
</template>
</Suspense>

八、小技巧

函数?表达式用法

1
2
if(props.ok?.() !==false){}
// ok是个function 为真 默认执行 返回值与false对比

样式设置

1
2
:class={selected: key ==='1'}
<div class="selected"></div>

REF

1
2
3
4
5
6
// ref
<div :ref="ref =>{ if(el) navItems[index] }"/>
const navItems = ref([])
onMounted(()=>{
navItems.value
})

获取宽高和位置

const { width , left } = el.getBoundingClientRect()
// 重命名
const { left:left1 } = el.getBoundingClientRect()

钩子的含义

onMounted onUpdated watchEffect

watchEffect() 会在挂载前就会执行,因为 有时候放到onMouned再执行

1
2
3
4
5
onMounted(()=>{
watchEffect(()=>{

})
})

TS泛型
const indicator = ref(null)

九、如何判断子组件的对象类型 用JS获取插槽内容

1
2
3
4
5
6
7
8
9
10
11
12
13
import Tab from './Tab.vue'
setup(props,context){
const defaults = const.slots.default()
console.log(defaults[0].type === Tab)
defaults.forEach((tag)=>{
if(tag.type !== Tab){
throw new Error('Tabs的子标签必须是Tab')
}
})
return{
defaults
}
}

十、一键部署SH

1
2
3
4
5
6
7
8
9
10
11
rm -rf dist
yarn build
cd dist
git init
git add.
git commit -m "update"
git brach -M master
git remote add origin git@github.com:name/x.git
git push -f -u origin master
cd -
echo http://...

十二、VUE2 = > VUE3

1、官方中文文档 https://v3.cn.vuejs.org/

2、工具 vue-codemode

十三、相关报错解决

sass报错

  1. 打开 package.json
  2. 把 dependencies 里的 sass 这一行,移到 devDependencies
  3. 重新运行 yarn install 或者 npm install 即可

报 vue/valid-template-root 错误

这个错是因为 VSCode 的 Vetur 插件还没支持 Vue 3,解决办法是在 VSCode 配置里添加一行 “vetur.validation.template”: false, 来关闭检查。

报 ‘X.vue’ is not a module. Vetur(2306) 错误

解决方法是在 X.vue 中添加一个