在Vue3中使用JSX
- 0
#讨论区
00条评论
实时对话
loading...
JSX,即JavaScript XML,是一种允许开发者在JavaScript代码中编写与HTML类似的结构的语法扩展,并能够通过诸如Babel这样的编译器转换为createElement
(React中)或createVNode
(Vue中)的函数调用,从而创建虚拟DOM。JSX结合了JavaScript的逻辑处理能力与标记语言的声明式编写模式,使得你可以在单个文件中处理UI和业务逻辑,实现组件的组织和复用。
JSX虽然在React和Vue中的使用方式非常相似,但还是存在一些差别:
React.createElement
或 react/jsx-runtime
,而Vue 3使用createVNode
。@vue/babel-plugin-jsx
。className
属性绑定,而for
属性在JSX中需要替换为htmlFor
。而在Vue中,则保持class
和for
的标准HTML属性使用。jsx
jsx
jsx
jsx
jsx
javascript
javascript
javascript
json
.tsx
结尾jsx
jsx
在 JSX 中,推荐以直接引入的形式使用组件。
jsx
类似于template
,在JSX中不能使用template
,会直接不渲染。
jsx
jsx
jsx
jsx
jsx
jsx
使用按需引入,Lego官方文档
jsx
typescript
json
jsx
jsx
const element = <h1>Hello, world!</h1>;
const name = 'c.chen';
const element = <h1>Hello, {name}</h1>;
const avatar = <img src={user.avatarUrl}></img>;
const avatar = user.avatarUrl ? <img src={user.avatarUrl} /> : null;
const avatar = user.avatarUrl && <img src={user.avatarUrl} />;
const img1 = <img style={{width:"200px"}}></img>;
const customStyle = {
width: "200px"
}
const img2 = <img style={customStyle}></img>;
// css module
import styles from './app.module.css';
const imgElement = <img class={styles.myImage} />;
const imgClass = <img class="my-image"></img>;
//babel.config.js
module.exports = {
presets: ['@vue/cli-plugin-babel/preset'],
};
if (vueVersion === 2) {
presets.push([require('@vue/babel-preset-jsx'), jsxOptions])
} else if (vueVersion === 3) {
plugins.push([require('@vue/babel-plugin-jsx'), jsxOptions])
}
//vite.config.ts
import vueJsx from '@vitejs/plugin-vue-jsx';
const config = defineConfig({
plugins: [
vue(),
vueJsx(),
]
}
//tscongfig.json
{
"jsx": "preserve",
"jsxImportSource": "vue"
}
// UI = fn(state)
function MyComponent(props, { slots, emit, attrs }) {
return <NButton>{props.message}</NButton>
}
const App = () => <div>111</div>;
<template>
<div>
<slot></slot>
<p>Count: {{ count }}</p>
<button ref="buttonRef" @click="increment">Increment</button>
<NInput
v-model="baseInfo.description"
/>
</div>
</template>
<script lang="ts" setup>
import { ref, defineProps, defineEmits, PropType } from 'vue';
import { NInput } from '@nio-fe/lego';
const props = defineProps({
modelValue: String as PropType<'large' | 'small'>
});
const emits = defineEmits(['update:modelValue']);
const count = ref(0);
const baseInfo = ref({
description: ''
});
const buttonRef = ref<HTMLButtonElement>();
// Define methods
const increment = () => {
count.value++;
};
const updateDescription = (value: string) => {
baseInfo.value.description = value;
emits('update:modelValue', value);
};
const externalMethod = () => console.log('External method called');
defineExpose({
externalMethod
});
</script>
import { defineComponent } from 'vue';
import Counter from './Counter';
export default defineComponent({
name: 'App',
setup() {
return () => (
<div>
<h1>Hello Vue 3 with TSX!</h1>
<Counter />
</div>
);
},
});
const App = () => (
name === 'cc' && <>
<span>I'm</span>
<span>Fragment</span>
</>
);
<NInput
v-model={[inputValue.value, ['trim']]}
/>
<NInput
modelValue={inputValue.value.trim()}
onUpdate:modelValue={newVal=>inputValue.value = newVal.trim()}
/>
const ComponentA = defineComponent({
setup(){
return ()=> <div>ComponentA</div>
}
})
const ComponentB = defineComponent({
setup(){
return ()=> <div>ComponentB</div>
}
})
const ColumnDiff = defineComponent({
setup() {
const components = {
'component-a': <ComponentA />,
'component-b': <ComponentB />,
};
const componentName = 'component-a';
const ComponentToRender = components[componentName];
return () => (
<>
<div class={'container mx-auto'}>
--1--
{ComponentToRender}
--2--
{ComponentToRender ? h(ComponentToRender) : null}
--3--
<ComponentToRender />
</div>
</>
)
}
})
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>
);
},
};
const app = createApp();
app.directive('highlight', {
mounted(el, binding) {
el.style.backgroundColor = binding.value;
},
});
app.directive('tooltip', NVTooltip)
app.directive('popconfirm', NVPopconfirm)
app.directive('loading', NVLoading)
app.component('my-component', {
setup() {
return () => (
<div v-highlight="'yellow'">
This will be highlighted in yellow.
</div>
);
},
});
app.mount('#app');
import { defineComponent, h } from 'vue';
// 引入子组件
import ChildComponent from './ChildComponent.vue';
export default defineComponent({
name: 'ParentComponent',
props:{
a:String,
},
setup(props, { attrs, slots, emit }) {
// 所有的父 props 都会以 props 参数的形式接收
// attrs 包含了非 props 的属性,例如 class, style, id 等
return () => (
<ChildComponent {...props} {...attrs}>
{slots.default ? slots.default() : ''}
</ChildComponent>
);
},
});
<div
class={css({
color: 'var(--n-text-secondary)'
})}
>
css in js style
</div>
//typings.d.ts
declare module '*.scss' {
const content: { [className: string]: string };
export default content;
}
{
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.scss"],
}
import styles from './demo.module.scss'
.header{
height: 80px;
&-left{
color: var(--n-text-primary);
}
}
<div class={styles.header}>
<div class={styles.headerLeft}>
name
</div>
</div>
const list = []
const app = list.length && list.map(item => )