技术咨询、项目合作、广告投放、简历咨询、技术文档下载
点击这里 联系博主
# vue3 + 组合式 api + typescript 注意事项
# vue3 使用 typescript/tsx 失败
- 修改 babel.config.js
module.exports = {
presets: [
"@vue/cli-plugin-babel/preset",
[
"@babel/preset-env",
{
targets: {
browsers: [
"last 3 Chrome versions",
"last 3 Firefox versions",
"Safari >= 10",
"Explorer >= 11",
"Edge >= 12",
],
esmodules: true,
},
modules: false,
},
],
],
plugins: ["@vue/babel-plugin-jsx"],
};
- 新增
shims-vue.d.ts
/* eslint-disable */
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
- 新增
shims-tsx.d.ts
import Vue, { VNode } from 'vue';
declare global {
namespace JSX {
// tslint:disable no-empty-interface
type Element = VNode;
// tslint:disable no-empty-interface
type ElementClass = Vue;
interface IntrinsicElements {
[elem: string]: any;
}
}
}
- 编写 tsx 代码
import { defineComponent } from "vue";
import HelloWorld from "./components/HelloWorld.vue";
export default defineComponent({
props: {
message: [String, Function] as PropType<string | (() => string)>,
},
setup(props) {
return () => {
const message = props.message;
return (
<div id="app">
<img alt="Vue logo" src="./assets/logo.png" width="25%" />
<HelloWorld msg={typeof message === "string" ? message : message()} />
</div>
);
};
},
});
# 引入 svg/png 等失败
错误信息:
ERROR in src/views/editor/controller/index.vue:9:22
TS2307: Cannot find module '@/assets/editor/page.png' or its corresponding type declarations.
7 | import { defineComponent, PropType } from 'vue';
8 | import CTLItem from './ctl-item';
> 9 | import PageIcon from '@/assets/editor/page.png';
解决办法:
在shims.d.ts
中新增:
declare module '*.svg'
declare module '*.png'
declare module '*.jpg'
declare module '*.jpeg'
declare module '*.gif'
declare module '*.bmp'
declare module '*.tiff'
# vue 中如何修改 svg 颜色
- 编写 svg 组件
import { defineComponent } from "vue";
export default defineComponent({
setup(props, { emit }) {
return () => (
<svg
class="svg-icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="3141"
width="40"
onClick={() => {
emit("click");
}}
>
<defs>
<style type="text/css"></style>
</defs>
<path
d="M236.864 64h472.96L896 261.12V848c0 61.856-54.72 112-114.848 112h-544.32C176.768 960 128 909.856 128 848V176c0-61.856 48.736-112 108.864-112zM672 128v133.856A26.144 26.144 0 0 0 698.144 288H832L672 128z m106.656 768c29.44 0 53.344-24.576 53.344-54.848V347.424H672c-29.44 0-53.344-24.544-53.344-54.848V128H245.344C215.904 128 192 152.576 192 182.848v658.304C192 871.424 215.872 896 245.344 896h533.312z"
p-id="3142"
></path>
</svg>
);
},
});
- 修改
fill
属性
.svg-icon {
&:hover {
fill: var(--xpage-mis--color-primary);
background-color: var(--xpage-mis-sidebar-hover-bg-colo);
}
}
# vue 常用指令 tsx/jsx 的实现
# v-bind
绑定标签属性。
注意点
- 属性的写法上和 HTML 存在区别,在写 JSX 的时候,所有的属性都是驼峰式的写法.如:className. 有些属性名不能直接绑定,如:for、class。for-> className for-> htmlFor
- data-* 和 aria-* 两类属性是和 HTML 一致的 data 系列是指自定义数据。 aria 系列是指一般是为不方便的人士提供的功能。
例 1
// 绑定span的title。
// 在jsx中没有必要要用ref,我就是说明一下可以这么用。
import { ref } from "vue";
export default () => {
const msg = ref("小火汁😂");
return <span title={msg.value}>走成华大道(鼠标停一哈看提示)</span>;
};
例 2
const placeholderText = "email";
const App = () => <input type="email" placeholder={placeholderText} />;
# v-show
const App = defineComponent({
data() {
return { visible: true };
},
render() {
return <input v-show={this.visible} type="text" placeholder="7777" />;
},
});
export default App;
# v-model
注意:如果想要使用参数,可以用一个参数, 但是如果用了两个参数,第二个参数需要为字符串!以作为参数名。 官方
readme
<input v-model={val} />
<input v-model={[val, ["modifier"]]} />
<A v-model={[val, "argument", ["modifier"]]} />;
//会变编译成:
h(A, {
argument: val,
argumentModifiers: {
modifier: true,
},
"onUpdate:argument": ($event) => (val = $event),
});
# v-models 传递多个参数
注意: 你应该传递一个二维数组给 v-models。
<A v-models={[[foo], [bar, "bar"]]} />
<A
v-models={[
[foo, "foo"],
[bar, "bar"],
]}
/>
<A
v-models={[
[foo, ["modifier"]],
[bar, "bar", ["modifier"]],
]}
/>;
//会变编译成:
h(A, {
modelValue: foo,
modelModifiers: {
modifier: true,
},
"onUpdate:modelValue": ($event) => (foo = $event),
bar: bar,
barModifiers: {
modifier: true,
},
"onUpdate:bar": ($event) => (bar = $event),
});
# 插槽
注意: 在 jsx/tsx 中,应该使用 v-slots 代替 v-slot
const A = (props, { slots }) => (
<>
<h1>{slots.default ? slots.default() : "foo"}</h1>
<h2>{slots.bar?.()}</h2>
</>
);
const App = {
setup() {
const slots = {
bar: () => <span>B</span>,
};
return () => (
<A v-slots={slots}>
<div>A</div>
</A>
);
},
};
// or
const App = {
setup() {
const slots = {
default: () => <div>A</div>,
bar: () => <span>B</span>,
};
return () => <A v-slots={slots} />;
},
};
// or
const App = {
setup() {
return () => (
<>
<A>
{{
default: () => <div>A</div>,
bar: () => <span>B</span>,
}}
</A>
<B>{() => "foo"}</B>
</>
);
},
};
# 使用 provide/inject
- 封装公共的 provide/inject
import { provide, inject } from "vue";
const EDITOR_PROVIDE = "editor";
export type EditorProvideType = {
currentCmp: any;
changeCurrentCmp?: (schema: any) => void;
};
/**
* 最外层组件暴露实例给下面的子组件
* @param state
*/
export function provideEditor(state: EditorProvideType): void {
provide<EditorProvideType>(EDITOR_PROVIDE, state);
}
/**
* 子组件获取顶层父组件提供的实例方法
* @returns
*/
export function injectEditor(): EditorProvideType | undefined {
return inject<EditorProvideType>(EDITOR_PROVIDE);
}
- 父组件 provide
setup() {
// 暴露实例给子组件
const state = reactive<EditorProvideType>({
currentCmp: null,
changeCurrentCmp(schema: XPageUISchemaType) {
state.currentCmp = schema;
},
});
provideEditor(state);
return {
...toRefs(state),
};
},
- 子组件 inject
setup() {
const state = reactive<{
list: any[];
}>({
list: [],
});
// inject需要在setup中
const editor = injectEditor();
return {
onWidgetAdd: (evt: SortableEvent) => {
// 记得在这里更新一下数据
if (evt.newIndex !== undefined) {
editor?.changeCurrentCmp?.(state.list[evt.newIndex]);
}
}
};
},
- 本文链接: https://mrgaogang.github.io/vue/vue%E4%BD%BF%E7%94%A8typescript%E6%97%B6%E9%97%AE%E9%A2%98%E9%9B%86.html
- 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 许可协议。转载请注明出处!