# vue3 初实践
- vue3 初实践
- 1.tsconfig.json 报错
- 2.vscode 中报错 vue 模板只能有一个根元素
- 3.vue 官方实例
- 4.script 中直接使用 setup
- 5.尤雨溪 Vue Function-based API RFC
- 6.ref
- 7.vue 中使用 Element-Plus
- 8.vue 项目,vscode 保存格式一直不起作用
- 9.vite 配置的项目,extensions 配置无用了
- 10.ref 和 reactive 的区别
- 11.defineComponent
- 12.setup
- 13.vue3 中的 Fragment
- 14.vue3 中 vite 不能直接使用 require
- 15.vue3 中使用 element-plus 的图标
- 16.vite 多页面打包
- 17.vue 中动态绑定 class
- 18.vue3 中使用 echarts
- 19.antdesign vue 中写了样式不加载的解决方法
# 1.tsconfig.json 报错
Flag 'importsNotUsedAsValues' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. Use 'verbatimModuleSyntax' instead.ts
可以通过在项目中添加以下命令来隐藏此警告:tsconfig.json
{
"compilerOptions": {
"ignoreDeprecations": "5.0",
....
}
}
2
3
4
5
6
# 2.vscode 中报错 vue 模板只能有一个根元素
由于 vue3 已经支持多个根元素了,所以代码并没有报错,而 vscode 中的 eslint 中的 vue 校验 vetur 还没有更新,还认为是 vue2 项目所以就报错了。
可见:https://github.com/vuejs/vetur/issues/2299#issuecomment-696015374
Vue 3 模板根只需要一个 element.eslint-plugin-vue (opens new window)
"vetur.validation.template": false,
"vetur.validation.script": false,
"vetur.validation.style": false,
2
3
# 3.vue 官方实例
https://cn.vuejs.org/examples/#markdown
# 4.script 中直接使用 setup
<script setup lang="ts">
import {ref} from 'vue'
let count = ref(0) // 响应式数据的话需要使用ref
const updateCount = () => count.value++
</script>
<template>
{{count}}
<button @click="updateCount">更新数据</button>
</template>
2
3
4
5
6
7
8
9
10
11
# 5.尤雨溪 Vue Function-based API RFC (opens new window)
import {ref, computed, watch, onMounted} from 'vue'
const App = {
template: `
<div>
<span>count is {{ count }}</span>
<span>plusOne is {{ plusOne }}</span>
<button @click="increment">count++</button>
</div>
`,
setup() {
// reactive state
const count = ref(0)
// computed state
const plusOne = computed(() => count.value + 1)
// method
const increment = () => {
count.value++
}
// watch
watch(
() => count.value * 2,
(val) => {
console.log(`count * 2 is ${val}`)
}
)
// lifecycle
onMounted(() => {
console.log(`mounted`)
})
// expose bindings on render context
return {
count,
plusOne,
increment,
}
},
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
设计动机是逻辑组合与复用、类型推导、打包尺寸
- 都写在 setup 中为了逻辑抽取更方便,不用某一个逻辑分散在 watch,methods 里面不好组合拿出来
- 更好的支持 ts,使用 ts 的类型推导
- 全写在 setup 中便于压缩,更易导出,tree-shaking 更容易
确实借鉴了 react hooks
setup(props)的参数是 props,props 是响应式的
ref()返回的是一个 value reference(包装对象),包装对象只有一个属性 value。包装对象的意义就在于提供一个让我们能够在函数之间以引用的方式传递任意类型值的容器;有了这样的容器,我们就可以在封装了逻辑的组合函数中将状态以引用的方式传回给组件。组件负责展示(追踪依赖),组合函数负责管理状态(触发更新)
包装对象在 template 模板中直接使用,不用加.value
没有包装的响应式对象 reactive api
computed、watch 均可以在其中直接用
watch 的第二个函数的第三个参数可以用来注册清理操作的函数
默认情况下,所有的 watcher 回调都会在当前的 renderer flush 之后被调用。这确保了在回调中 DOM 永远都已经被更新完毕
生命周期函数有对应的 onXXX 函数
import { onMounted, onUpdated, onUnmounted } from 'vue'
类型推导
import { defineComponent } from 'vue'
const MyComponent = defineComponent({ // props declarations are used to infer prop types props: { msg: String, }, setup(props) { props.msg // string | undefined // bindings returned from setup() can be used for type inference // in templates const count = ref(0) return { count, } }, })
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16defineComponent
从概念上来说和 2.x 的Vue.extend
是一样的,但在 3.0 中它其实是单纯为了类型推导而存在的,内部实现是个 noop(直接返回参数本身)。它的返回类型可以用于 TSX 和 Vetur 的模版自动补全。如果你使用单文件组件,则 Vetur 可以自动隐式地帮你添加这个调用Vue 提供的
PropType
类型可以用来声明任意复杂度的 props 类型,但需要用as any
进行一次强制类型转换:props: { options: (null as any) as PropType<{ msg: string }> }
1
2
3尤大意思不用很担心会写出很多的面条代码,因为现在的新 api 更容易去组织代码去抽取函数
# 6.ref
ref 是一个函数,定义一个响应式的数据
返回一个 Ref 对象,对象中有一个 value 属性
html 模版中不需要写.value
一般用来定义一个基本类型的响应式数据
# 7.vue 中使用 Element-Plus
# 1.vue3 中使用 Element-Plus 覆盖默认样式不起作用
style 的地方不能使用 scope
# 2.使用 css 变量来更改样式
通过 CSS 变量设置 (opens new window)
<el-card
class="box-card"
shadow="never"
style="--el-card-padding:10px"
></el-card>
2
3
4
5
# 8.vue 项目,vscode 保存格式一直不起作用
原来是项目中没有.editorconfig 文件。
# 9.vite 配置的项目,extensions 配置无用了
vite 中导入.vue 文件时后缀不能省,配置 extensions 也不行,官方已经不允许不使用 vue 文件后缀导入了
https://github.com/vitejs/vite/issues/178 (opens new window)
# 10.ref 和 reactive 的区别
ref 是包装基本类型为响应式数据
reactive 是包装对象为响应式数据,Proxy 对象的数据
如果使用 ref 包装数组/对象,内部会自动将对象/数组转为 reactive 的代理对象
# 11.defineComponent
纯粹是为了 ts 类型提示的组件
比如写上 defineComponent 之后,其中 setup 的参数 props 就可以有类型提示了
# 12.setup
setup 在执行的时候,组件还没有创建出来,也就是 this 是 undefined,如此就不能通过 this 去调用 data/computed/methods/props 中的相关内容了
data 和 setup 或者 methods 和 setup 中的方法会合并,如果相同的话,setup 中的优先级高
setup 的参数:
setup(props,context){
// context里面是attrs,slot,emit
}
2
3
# 13.vue3 中的 Fragment
开始看到这个的时候以为和 react 中一样的用法,所以直接就在循环外使用了,结果控制台一直报警告,后来看了一下,vue3 中的这个是为了解决根元素上只能有一个元素的问题,现在 vue3 可以有多个了,当你写多个元素的时候,vue3 内部直接会给你自动加上一个 fragment,但是在页面元素那里不展示,而你可以在 devtool 中看到;
在 vue 中像 react 的一样用法可以使用<template></template>
,这效果和 React.Fragment 是一样的
# 14.vue3 中 vite 不能直接使用 require
vite 静态资源处理:https://vitejs.cn/guide/assets.html#new-url-url-import-meta-url (opens new window)
const imgUrl = new URL('./img.png', import.meta.url).href
document.getElementById('hero-img').src = imgUrl
2
3
这在现代浏览器中能够原生使用 - 实际上,Vite 并不需要在开发阶段处理这些代码 在生产构建时,Vite 才会进行必要的转换保证 URL 在打包和资源哈希后仍指向正确的地址。
在模板中直接使用图片的话,可以使用 import 在顶上引入图片,再放在 img 的 src 处:
<script>
import img1 from '@/images/img1.png'
</script>
<template>
<img :src="img1" />
</template>
2
3
4
5
6
# 15.vue3 中使用 element-plus 的图标
npm install @element-plus/icons
import {ArrowRight} from '@element-plus/icons'
// 使用
;<el-icon>
<arrow-right />
</el-icon>
2
3
4
5
6
# 16.vite 多页面打包
envDir:'../',
build: {
rollupOptions: {
input: {
main: resolve(__dirname, 'index.html'),
1679296960: resolve(__dirname, 'newsPage/1679296960.html'),
},
},
},
2
3
4
5
6
7
8
9
遇到问题:一直说找不到
https://blog.csdn.net/nithumahel/article/details/126701673
打包出错:
[vite]: Rollup failed to resolve import "src/main.js" from "index.html". This is most likely unintended because it can break your application at runtime. If you do want to externalize this module explicitly add it to
build.rollupOptions.external
error during build: Error: [vite]: Rollup failed to resolve import "src/main.js" from "index.html". This is most likely unintended because it can break your application at runtime. npm ERR! land-page@0.0.0 build_local:vite build
npm ERR! Exit status 1 npm ERR! npm ERR! Failed at the land-page@0.0.0 build_local script. npm ERR! This is probably not a problem with npm. There is likely additional logging output above.npm ERR! A complete log of this run can be found in: npm ERR! C:\Users\admin\AppData\Roaming\npm-cache_logs\2022-09-05T03_36_40_610Z-debug.log
<script type="module" src="src/main.js"></script>
改成
<script type="module" src="./src/main.js"></script>
2
3
# 17.vue 中动态绑定 class
# 1.多个 class,其中一个是动态的
<div :class="['main-content', 'news', isSmall ? 'small-screen' : '']">
</div>
2
# 18.vue3 中使用 echarts
npm install echarts
在 App.vue 中引用:
import * as echarts from echarts
import {provide} from 'vue'
provide('echarts',echarts)
2
3
4
在其他文件中使用
<script lang="ts" setup>
import {onMounted, onBeforeUnmount, inject} from 'vue'
let echarts: any = inject('echarts')
let myChart: echarts.ECharts | null = null
const handleResize = () => {
if (myChart) {
myChart.resize()
}
}
onMounted(() => {
myChart = echarts.init(document.getElementById('bussinessMap'))
// 绘制图表
if (myChart) {
myChart.setOption({
title: {text: '总用户量'},
tooltip: {},
xAxis: {
data: ['12-3', '12-4', '12-5', '12-6', '12-7', '12-8'],
},
yAxis: {},
series: [
{
name: '用户量',
type: 'line',
data: [5, 20, 36, 10, 10, 20],
},
],
})
}
window.addEventListener('resize', handleResize)
})
onBeforeUnmount(() => {
window.removeEventListener('resize', handleResize)
})
</script>
<template>
<div id="lineChart" class="line-chart"></div>
</template>
<style lang="less" scoped>
.line-chart {
width: 100%;
height: 600px;
}
</style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# 19.antdesign vue 中写了样式不加载的解决方法 (opens new window)
在 vue 组件里,lang 设置为 less,在 style 设置为 scoped 的时候 ,在写样式有时候对子组件不生效。如果想让某些样式对子组件生效,可以使用 /deep/ 深度选择器。
代码:
/deep/.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-item,
.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-submenu {
margin-top: 0px;
margin-bottom: 0;
padding: 0px 22px;
}
2
3
4
5
6
# 19.1[@vue/compiler-sfc] the >>> and /deep/ combinators have been deprecated. Use :deep() instead.
//第一种
// 原样式
/deep/ .hiprint-printElement-type > li > ul > li > a {
padding: 4px 4px;
color: #1296db;
line-height: 1;
height: auto;
text-overflow: ellipsis;
}
// 修改后
:deep(.hiprint-printElement-type > li > ul > li > a) {
padding: 4px 4px;
color: #1296db;
line-height: 1;
height: auto;
text-overflow: ellipsis;
}
//第二种
// 原样式
/deep/ .hiprint-printElement-type > li > ul > li > a {
padding: 4px 4px;
color: #1296db;
line-height: 1;
height: auto;
text-overflow: ellipsis;
}
// 修改后
::v-deep(.hiprint-printElement-type > li > ul > li > a) {
padding: 4px 4px;
color: #1296db;
line-height: 1;
height: auto;
text-overflow: ellipsis;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35