vue3+typescript实战项目中,vue3相关内容
createApp(App).component 失效
报错:Component provided template option but runtime compilation is not supported
[Vue warn]: Component provided template option but runtime compilation is not supported in this build of Vue. Configure your bundler to alias "vue" to "vue/dist/vue.esm-bundler.js".
at <Test message=1 >
at <App>
解决方案:
方案一:index.html模板,此类可使用component注册全局组件。(不推荐)
//main.ts中
import { createApp } from 'vue'
import App from './App.vue'
app.component('Test', {
template: '#test', //注意此行
})
app.mount('#app')
在html中有id为test的可用模板
<div id="test"> <!-- 此处模板生效 -->test123</div>
<div id="app"></div>
方案二:alias
vue.config.js,alias,vue换一种模式;我使用的webpack启动vue3. 因为使用vite经常热启动会挂
module.exports={
configureWebpack: config=>{
config.resolve = {
alias:{
vue:"vue/dist/vue.esm-bundler.js" // 这个加上,重新启动就可以使用了
}
}
}
}
main.ts文件
import { createApp } from 'vue'
import App from './App.vue'
// import store from './store'
const app = createApp(App)
app.component('button-counter', {
template: `<button>You clicked me times.</button>`
})
app.mount('#app')
App.vue文件
<template>
<button-counter></button-counter>
</template>
原理大概是vue3的compiler 模式和runtime模式的区别吧! 但是我的store用不了了。
方案三:app.component
main.ts
const app = createApp(App);
import Title from './components/Title.vue'
app.component('newtitle',Title)
Title.vue
<template>
<div>内容标题</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name: 'Title',
})
</script>
ref,reactive 针对数组的用法
const componentList: Record<string, any> = ref([])
componentList = res.data.componentList //错误用法
componentList.value = res.data.componentList // 使用.value改变其值 才有效
directive 【vue3有修改】
- app.directive 注册方式有所变化
- bind被移除,可使用mounted, unbind 对应 unmounted
vue2 v-clickoutside demo
/**
* 点击元素外部,元素关闭
* v-clickoutside绑定
*/
export function clickoutside(){
return {
//初始化指令
bind(el,binding,vnode){
function documentHandler(e){
//这里判断点击的元素是否是本身,是本身,则返回
if(el.contains(e.target)){
return false;
}
//判断指令中是否绑定了函数
if(binding.expression){
//如果绑定了函数,则调用那个函数,此处binding.value就是handleClose方法
binding.value(e);
}
}
//给当前元素绑定个私有变量,方便在unbind中可以解除事件监听
el.__vueClickOutside__ = documentHandler;
document.addEventListener("click",documentHandler);
},
update(){},
unbind(el,binding){
//解除事件监听
document.removeEventListener("click",el.__vueClickOutside__);
delete el.__vueClickOutside__;
}
}
}
vue3 v-clickoutside demo
export function clickoutside() {
return {
//初始化指令
mounted(el: any, binding: any) {
function documentHandler(e: any) {
//这里判断点击的元素是否是本身,是本身,则返回
if (el.contains(e.target)) {
return false;
}
//判断指令中是否绑定了函数
if (binding.value) {
//如果绑定了函数,则调用那个函数,此处binding.value就是handleClose方法
binding.value(e);
}
}
//给当前元素绑定个私有变量,方便在unbind中可以解除事件监听
el.__vueClickOutside__ = documentHandler;
document.addEventListener("click", el.__vueClickOutside__);
},
unmounted(el: any) {
//解除事件监听
document.removeEventListener("click", el.__vueClickOutside__);
delete el.__vueClickOutside__;
}
}
}
//引用方式
import { clickoutside, copy } from '@/common/directive'
const clickoutsideObj: Record<string, any> = clickoutside()
app.directive('clickoutside', clickoutsideObj)
$refs 【vue3有修改】
<div :ref="el => { divs[i] = el }></div>
setup(){
const allComP = ref([])
onUpdated(() => {
console.log('allComP.value', allComP.value)
})
return {allComP}
}
对应文档 v3.vuejs.org/guide/compo…
slot 【vue3有修改】
vue2-slot demo
//父组件
<SonComponent>
<template slot='toTop'>
<div class="scrollWrap-toTop fixed-box"></div>
</template>
</SonComponent>
//SonComponent
<template>
<slot name='toTop'></slot>
</template>
vue3-slot demo
//父组件
<SonComponent>
<template v-slot:toTop> //区别
<div class="scrollWrap-toTop fixed-box"></div>
</template>
</SonComponent>
//SonComponent内部
<template>
<slot name="toTop"></slot>
</template>
报错:runtime-core.esm-bundler.js?5c40:2834 Uncaught (in promise) TypeError: Cannot read property 'created' of undefined
- 我碰到的问题是,自定义指令未注册,但先提前使用了
- 一般是标签上的属性或绑定事件未提前注册时会报错
模块无法显示,无提示
解决方案可参考 suspense ,但我碰到的情况是 component v-for="item in list" is:item
async setup(){ //加了async貌似就会有问题。暂无解决方案
}
vue3+typescript实战项目中,ts相关错误提示
Object is possibly 'null'.
解决方案 as 对应类型
const scrollElement = document.querySelector('body')
scrollElement.scrollTop
//解决方案
const scrollElement = document.querySelector('body') as HTMLElement
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type
解决方案 附加类型
const componentsMap = {
title: Title,
abstract: Abstract
}
Object.keys(componentsMap).forEach(val => {
app.component(val, componentsMap[val]) //componentsMap[val] 提示的错误
})
//解决方案
const componentsMap :any //方案1
const componentsMap :Record<string, DefineComponent> //方案2
Property 'xxx' does not exist on type 'Window & typeof globalThis'
解决方案 window.d.ts
interface Window {
getAccount(): string | number | never
}
//使用
window.getAccount()
出错的可能是由于你更改了d.ts文件但 vscode 未重新编译,可重新编译试一下
全局缩写 --- Record<string, any>加个
type Obj = Record<string, any>
表达Object,对象内部任意成员
interface A{
[params: string]:any
}
No overload matches this call.Overload 1 of 2, '(...items: ConcatArray[]): never[]', gave the following error.
type Item = {
time: number;
};
const list = [].concat([{ time: 123 }]); // time会报错
解决方案一:
const list = ([] as Item[]).concat([{ time: 123 }]);
解决方案二:
const initList: Item[] = []
const list = initList.concat([{ time: 123 }]);
Argument of type 'Record<string, any> & { isNew: boolean; }' is not assignable to parameter of type 'never'.
报错场景
const list = ref([]);
const list.value.unshift({}) //报错
解决方案
const allListModule: Record<string,any>[] = []
const allList = ref(allListModule)
const allList.value.unshift({})
Property 'forEach' does not exist on type 'HTMLCollectionOf<Element>'
解决方案
const frameZones = Array.from(document.querySelectorAll('path.frame-zone'));
frameZones.forEach((...) => {});
'this' implicitly has type 'any' because it does not have a type annotation.
vue2.x 及 各类eslint报错汇总
大多数都是eslint报错
1:1 error Parsing error: Unexpected token <
Parsing error: Unexpected character '@'
使用 .eslintrc.js 做eslint的项目 保留 'plugin:vue/essential', 其他注释
module.exports = {
root: true,
env: {
node: true
},
'extends': [
'plugin:vue/essential', //这行起作用 error Parsing error: Unexpected token <
'eslint:recommended',
'@vue/typescript/recommended' //Parsing error: Unexpected character '@'
],
parserOptions: {
ecmaVersion: 2020
},
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
}
}
No overload matches this call.The last overload gave the following error.
export default defineComponent({
name: 'Title',
props: {
propData: {
title: '', //报错. 基础prop语法使用错误
},
},
setup() {
console.log(`title`)
},
})
typescript vue emitter.js 不起效。broadcast 不起效,dispatch不起效
案例代码如下
@Component
export default class HelloWorld extends Vue {
componentName = 'HelloWorld333'
}
问题在于要注册comoponentName需如下写法
@Component({
componentName:'realComponentName' //这样写才起效
})
export default class HelloWorld extends Vue {
componentName = 'HelloWorld333'
}
原理:class-component.vuejs.org/guide/class…
vue-cli sourceMap无法打断点;debugger无法定位;
如下图:无法打断点,且查找出来的代码块在 webpack-internal:// 开头的代码中
- 解决方案
//vue.config.js
configureWebpack: {
devtool: 'source-map',
}
关闭eslint中的warn。停止输出eslint中的warn,配置warn为0。
//.eslintrc.js文件
module.exports = {
rules: {
warn: 0
},
};
文件全局取消eslint关注
- 文件头部加 /* eslint-disable */ 亲测有效
vue3.x之各类API
computed 有两种注册方式
- 只读
import { defineComponent, computed,ref } from 'vue'
export default defineComponent({
name:'Test',
setup(){
const count = ref(1);
const plusOne = computed(()=> count.value + 1})
console.log(plusOne.value)
plusOne.value++ // 报错
}
})
- 可读可写
const plusOne = computed({
get:()=> count.value +1,
set:(val)=>{
count.value = val -1
}
})
vue2.x之各类API
Provide及Inject,vue-property-decorate版
- 遵循几个规则:
- provide、inject
- father组件注册 provide,son组件可以通过Inject获取对应属性
// father组件
@Provide() provide = 1
//son组件
@Inject({ from: 'provide', default: 0 }) provide!: number
- 父子组件改变对应值时,是独立的内存单元。互不影响
- ProvideReactive、InjectReactive
- father注册ProvideReactive,son组件可使用 @InjectReactive获取对应属性。
- father改变值时,子组件可使用watch捕捉到
- 子组件无法更改对应值
//father组件
@ProvideReactive() provideReactive = 1
//son组件
@InjectReactive({ from: 'provideReactive' }) provideReactive!: number
@Watch('provideReactive')
onChangeProvideReactive() {
console.log(`%c 特殊输出watch provideReactive`, 'color:#ff0000') //可捕捉因
}
test() {
this.provide = 2 //可修改
console.log(`%c change provide`, 'color:#ff0000', this.provide)
this.provideReactive = 2 //修改后不生效
console.log(`%c change provideReactive`, 'color:#ff0000', this.provideReactive)
}
vue2 + ts 进阶必备库
vue-class-component
class装饰器 vue-class-component
vue-property-decorator
npm i vue-class-component vue-property-decorator -D
class及其他装饰器,base(vue-class-component):vue-property-decorator
*.vue中支持ts语法,需在script上加lang=ts
vue-cli3 配置感悟
configureWebpack
如果这个值是一个对象,则会通过 webpack-merge 合并到最终的配置中。
总算理解了。无非就是把该在 {配置里的东西} 写到了这个属性中去
chainWebpack
允许对内部的 webpack 配置进行更细粒度的修改。
无非就是配合 vue inspect 去修改对应的配置;
vue.config.js
module.exports = {
chainWebpack: config => {
// GraphQL Loader
config.module
.rule('graphql')
.test(/\.graphql$/)
.use('graphql-tag/loader')
.loader('graphql-tag/loader')
.end()
// 你还可以再添加一个 loader
.use('other-loader')
.loader('other-loader')
.end()
}
}
各种API地址
sketch图使用中碰到问题汇总
- sketch中px与百分比切换显示快捷键为 Alt