相信很多同行也有这个问题
- 就记得组件的好像有一个方法,但是方法具体的名字记得很模糊,然而这个组件又是很长很大几千行,去找方法都要找好久☻,这个时候就会想要是有提示就好了🙃
vue2对于typescript的支持不是很友好,但是也提供了一个class类形式
的编写方式接入typescript,不过这里不讨论这个,而是就是旧的vue项目,不是用的class形式编写的项目。
用的字面量形式定义的vue组件我也想要提示
🥺
试过好几种方法,最后有一种虽然写起来不是很好,但是也搞定了问题😄
代码
webpack配置
其实这个是在vue.config.js中的chainWebpack方法中
config.module
.rule('ts')
.test(/.(ts|tsx)$/)
.exclude.add(resolve('node_modules'))
.end()
.use('babel-loader')
.loader('babel-loader')
.end()
.use('ts-loader')
.loader('ts-loader')
.options({
appendTsSuffixTo: [/.vue$/],// 额外添加vue的支持
transpileOnly: true // 只用于编译
})
.end()
vue组件
这是我对vue-treeselect的一个包装
<template>
<VueTreeselect
v-bind="$attrs"
v-on="$listeners"
class="vueTreeSelectMini vueTreeSelectSmall"
v-model="syncValue"
:options="options"
:placeholder="placeholder"
:normalizer="normalizerCom"
:noChildrenText="noChildrenText"
:noOptionsText="noOptionsText"
:noResultsText="noResultsText"
:valueConsistsOf="valueConsistsOf"
:appendToBody="appendToBody"
:zIndex="zIndex"
@input="inputCom"
@open="openCom"
>
<template #after-list v-if="$slots.afterList">
<slot name="after-list"></slot>
</template>
<template #before-list v-if="$slots.beforeList">
<slot name="before-list"></slot>
</template>
<template #option-label="params" v-if="$slots.optionLabel">
<slot name="option-label" v-bind="params"></slot>
</template>
<template #value-label="params" v-if="$slots.valueLabel">
<slot name="value-label" v-bind="params"></slot>
</template>
</VueTreeselect>
</template>
<script lang="ts">
import VueTreeselect from '@riophae/vue-treeselect'
// 导入treeSelect样式
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
import {PropType} from "vue/types/options";
import typeOfUtils from "../../utils/type-of-utils";
import PopupManager from "element-ui/lib/utils/popup/popup-manager";
import {Props, PropsDefault} from './Type'
export default {
name: "TreeSelect",
components: {
VueTreeselect
},
props: {
value: {
type: [String, Number, Array],
default: () => ''
},
options: {
type: Array,
default: () => []
},
props: {
type: Object as PropType<Props>,
default: (): Props => PropsDefault
},
normalizer: Function,
loadOptions: Function,
placeholder: {
type: String,
default: '请选择'
},
noChildrenText: {
type: String,
default: '暂无子节点'
},
noOptionsText: {
type: String,
default: '没有可用选项'
},
noResultsText: {
type: String,
default: '未匹配到结果'
},
valueConsistsOf: {
type: String as PropType<'ALL'>,
default: 'ALL'
},
appendToBody: {
type: Boolean,
default: true
},
},
computed: {
syncValue: {
set(val) {
this.$emit('input', val)
},
get() {
return this.value
}
},
},
data() {
return {
zIndex: undefined
}
},
methods: {
normalizerCom(node) {
if (this.normalizer) {
return this.normalizer(node)
}
const props = {
...PropsDefault,
...this.props
}
if (!this.loadOptions) {
if (typeOfUtils.isEmpty(node[props.children])) {
return {
id: node[props.value],
label: node[props.label],
children: undefined
}
}
}
return {
id: node[props.value],
label: node[props.label],
children: node[props.children],
}
},
inputCom(val) {
this.$emit('input', val)
},
openCom(e) {
if (this.appendToBody) {
this.zIndex = PopupManager.nextZIndex()
}
this.$emit('open', e)
}
}
}
</script>
<style lang="scss">
.vue-treeselect__portal-target.vue-treeselect.vue-treeselect--searchable.vue-treeselect--open-below.vue-treeselect--append-to-body{
min-width: 500px;
}
.el-form-item{
&.el-form-item--small{
/* small */
.vueTreeSelectSmall .vue-treeselect__control {
height: 32px;
}
.vueTreeSelectSmall .vue-treeselect__control .vue-treeselect__value-container {
height: 32px;
display: block;
}
.vueTreeSelectSmall
.vue-treeselect__control
.vue-treeselect__value-container
.vue-treeselect__placeholder {
font-size: 13px;
}
.vueTreeSelectSmall
.vue-treeselect__control
.vue-treeselect__value-container
.vue-treeselect__single-value {
line-height: 32px;
font-size: 13px;
}
}
&.el-form-item--mini{
/* mini */
.vueTreeSelectMini .vue-treeselect__control {
height: 26px;
}
.vueTreeSelectMini .vue-treeselect__control .vue-treeselect__value-container {
height: 26px;
display: block;
}
.vueTreeSelectMini
.vue-treeselect__control
.vue-treeselect__value-container
.vue-treeselect__placeholder {
font-size: 12px;
}
.vueTreeSelectMini
.vue-treeselect__control
.vue-treeselect__value-container
.vue-treeselect__single-value {
line-height: 26px;
font-size: 12px;
}
}
}
//.vue-treeselect{
// .vue-treeselect__control{
// background-color: $--input-bg-color;
// border: 1px solid $--popper-border-color;
// }
// .vue-treeselect__single-value{
// color: $--input-font-color;
// }
//}
//.vue-treeselect--open-below .vue-treeselect__menu{
// background-color: $--popper-bg-color;
// color: $--popper-font-color;
// .vue-treeselect__option--highlight{ // 高亮
// background-color: $--popper-bg-color-hover;
// color: $--popper-font-color-hover;
// .vue-treeselect__option-arrow-container{
// svg{ // 箭头颜色
// color: $--popper-font-color-hover;
// }
// }
// }
//}
//.vue-treeselect--single{
// .vue-treeselect__option--selected{
// background-color: $--tree-select-bg-color-hover;
// color: #409EFF;
// &:hover{
// background-color: $--popper-bg-color-hover;
// }
// }
//}
</style>
类型文件
// @ts-nocheck
// vue类型文件,用于提示
/**
* 用法,这个文件一定要单独写,不然会编译进去
* import type {IndexType} from "./indexVueType";
* const test = {} as typeof IndexType
*
* 这样就不会编译到代码
*
*
*
* 如果需要ref也有提示
* 在计算属性里面写一个tip板的
* $refsTip(){
* return this.$refs
* }
*/
import Vue from 'vue'
import Index from './index.vue'
const v = Vue.extend(Index)
export const IndexType = new v()
主要看这里
效果
组件中引入
<template>
<div>
<TreeSelect ref="TreeSelectRef"></TreeSelect>
</div>
</template>
<script lang="ts">
// @ts-nocheck
import TreeSelect from "../local_modules/ZhiXinLib/components/TreeSelect/index.vue";
export default {
name: 'EmptyHome',
components: {TreeSelect},
data(){
return{
}
},
created() {
},
methods:{
}
}
</script>
<style scoped lang="scss">
</style>
组件中引入这个不需要那个类型定义文件,不过好像只有在webstorm中才会有提示
ts文件引入
- 这个是在组件内部使用类型文件
- 这个是在纯ts中使用
这些都是没有问题的,不过我也就是在webstorm上测试了,vscode作为亲儿子应该也支持吧,要是不支持就尴尬了🤣
问题
既然多了一个文件这个文件的代码会不会执行,先上结论不会哈
vite启动
vite是不需要配置typescript的,直接可以用
在类型文件中插入一个输出语句
控制台并没有输出这个语句
这里我们删掉type,建议不要删除
控制台也是没有输出的
webpack启动
webpack启动也是同样的效果,我就不截图了
原理
- 这个就是利用vue.extend和实例化
也就是这个样子
const v = Vue.extend(Index)
export const IndexType = new v()
这个index就是vue组件
- 这里一个很重要的点,就是typeof,
不加这个是会报错的
- 因为都是用的ts类型,所以在编译过程中,这个文件引入最后就没了,所以这个文件不会被执行,可以放心大胆的用
- 这个文件的头部一定要加上
//@ts-nocheck
,不让ts去检测这个文件,不然会报红(IED给你爆红)
最后
欢迎关注公众号致心空间
:O(∩_∩)O😁