Home > Article > Web Front-end > Detailed explanation of how to use JSX in Vue3+Vite
Vue How to use JSX in Vite? The following article will introduce to you how to use JSX in Vue3 Vite. I hope it will be helpful to you!
[Related recommendations: vuejs video tutorial, web front-end development】
JSX (JavaScript and XML), is an HTML-in-JavaScript syntax extension first introduced in React. JSX is a great way to describe how a UI should behave in the essence of how it should interact. JSX is an extension of JavaScript syntax, so HTML-like code can coexist with JS. For example:
const button = <MyButton color="blue" shadowSize={2}> Click Me </MyButton>
The button constant is called a JSX expression. We can use this to render the 3c45ec991a34a5c936634b431885c5ff
tag in our application. Browsers cannot read and parse JSX directly. The JSX expression looks like this after being compiled (with tools like Babel or Parcel):
React.createElement( MyButton, {color: 'blue', shadowSize: 2}, 'Click Me' )
In fact, JSX is just syntactic sugar for the React.createElement(component, props, ...children) function. You can skip the compilation step by writing the UI yourself using React.createElement(). However, doing so loses the declarative benefits of JSX and the code becomes harder to read. Compilation is an extra step in the development process, but many developers in the React community believe the readability of JSX is worth it. Additionally, popular tools make JSX-to-JavaScript compilation part of their setup process. You don't have to configure compilation yourself unless you want to. If you want to test what some specific JSX will be converted into JavaScript, you can try using the Online Babel compiler.
React does not require the use of JSX. Not using JSX in React is more convenient when you don't want to configure JSX compilation in the build environment. For example, code written in JSX:
class Hello extends React.Component { render() { return <div>Hello {this.props.toWhat}</div>; } } const root = ReactDOM.createRoot(document.getElementById('root')); root.render(<Hello toWhat="World" />);
can be written as code without JSX:
class Hello extends React.Component { render() { return React.createElement('div', null, `Hello ${this.props.toWhat}`); } } const root = ReactDOM.createRoot(document.getElementById('root')); root.render(React.createElement(Hello, {toWhat: 'World'}, null));
Vue uses The single-file component integrates the template, related scripts and CSS into a single file ending in .vue. These files are ultimately processed by JS packaging or build tools (e.g. Webpack, Vite). The
d477f9ce7bf77f53fbcf36bec1b69b7a
element contains all the markup structure and component display logic. The template can contain any valid HTML, as well as Vue-specific syntax. By setting thelang
attribute of thed477f9ce7bf77f53fbcf36bec1b69b7a
tag, for example, you can use the Pug template by setting885a744315c58b9af712dd38b4d61be6
Replaces standard HTML.The
3f1c4e4b6b16bbbd69b2ee476dc4f83a
tag in the .vue file contains all non-display logic in the component and needs to export a JS object by default. This object is where components are registered locally, properties are defined, local state is handled, methods are defined, etc. During the build phase this object containing the template will be processed and converted into a Vue component with a render() function.The CSS style of the component is written in the
c9ccee2e6ea535a969eb3f532ad9fe89
tag. If thescoped
attribute is added, Vue will limit the scope of the style to the content of the single-file component. inside. This is a solution similar to CSS-in-JS, but allows writing pure CSS. If you selected the CSS preprocessor when creating your project via the CLI, you can add thelang
attribute to thec9ccee2e6ea535a969eb3f532ad9fe89
tag so that Webpack can process the content at build time.
Although jsx was first introduced by React, JSX syntax does not actually define runtime semantics and can be compiled into various output forms. If you have used JSX syntax before, please note that Vue’s JSX compilation method is different from the JSX compilation method in React, so you cannot use React’s JSX compilation in Vue applications. Some notable differences from React JSX syntax include:
class
和 for
作为 props - 不需要使用 className
或 htmlFor
。Vue 的类型定义也提供了 TSX 语法的类型推导支持。当使用 TSX 语法时,确保在 tsconfig.json
中配置了 "jsx": "preserve"
,这样的 TypeScript 就能保证 Vue JSX 语法编译过程中的完整性。
vite 官方提供了官方的插件来支持在 vue3 中使用 jsx/tsx,直接安装就行。
npm i @vitejs/plugin-vue-jsx -D
安装完之后在 vite.config.js 文件中的 plugins 字段中添加 jsx 支持:
import vueJsx from "@vitejs/plugin-vue-jsx"; export default defineConfig({ plugins: [ vueJsx(), ] })
这样就可以在项目中使用 jsx/tsx 了。
在项目中新建 jsx 或 tsx 后缀的文件,语法和 js 文件类似,但是和 .vue 文件中的 3f1c4e4b6b16bbbd69b2ee476dc4f83a
标签一样需要默认导出一个 JS 对象。该对象是在本地注册组件、定义属性、处理本地状态、定义方法等的地方。
import HelloWorld from './HelloWorld.vue' export default { setup() { return () => <HelloWorld msg="11" />; }, };
1、插值。与 vue 模板语法中的插值一样,但是双大括号 {{}} 变为了单大括号 {}。大括号内支持任何有效的 JavaScript 表达式,比如:2 + 2,user.firstName,formatName(user) 等。
// 模板语法 <span>{{ a + b }}</span> // jsx/tsx <span>{ a + b }</span>
2、class 类名绑定。有两种方式,使用模板字符串或者使用数组。
// 模板字符串 <div className={ `header ${ isBg ? 'headerBg' : '' }` }>header</div> // 数组 <div class={ [ 'header', isBg && 'headerBg' ] } >header</div>
3、style 样式绑定。需要使用双大括号。
const color = 'red' const element = <sapn style={{ color, fontSize: '16px' }}>style</sapn>
4、条件渲染。由于 jsx 本身具有 js 语法,所以不再需要使用 v-if 指令,使用 if/else 和三元表达式都可以实现。但是支持 v-show 指令。
const element = (name) => { if (name) { return <h1>Hello, { name }</h1> } else { return <h1>Hello, Stranger</h1> } } const element = icon ? <span class="icon"></span> : null; // 以上代码等效于: const element = icon && <span class="icon"></span>;
5、列表渲染。同样,由于 jsx 本身具有 js 语法,所以不再需要使用 v-for 指令,使用 JS 数组的 map 方法即可。
const listData = [ {name: 'Tom', age: 18}, {name: 'Jim', age: 20}, {name: 'Lucy', age: 16} ] return () => ( <div> <div class={'box'}> <span>姓名</span> <span>年龄</span> </div> { prop.listData.map(item => <div class={'box'}> <span>{item.name}</span> <span>{item.age}</span> </div> }) </div> )
6、标签属性绑定。也是使用大括号包裹,不能使用 v-bind 指令。而 vue 组件中通过 7a49b8a1571104a37acffe1450d6cc1e16b28748ea4df4d9c2150843fecfba68
批量绑定标签属性,在 JSX 中需要使用 04eaf629e1aa69a83352c6b37941496316b28748ea4df4d9c2150843fecfba68
。
const href = 'https://cn.vuejs.org/' const element = <a href={href}>Vue3</a>
7、事件绑定。使用的也是 单大括号 {},不过事件绑定不是以 @为前缀了,而是改成了 on,与原生相同。例如:click 事件是 onClick 或 onclick。
const confirm = () => { // 确认提交 } <button onClick={confirm}>确定</button>
如果要带参数,需要使用箭头函数进行包裹:
const confirm = (name) => { // 确认提交 } <button onClick={() => confirm('Are you sure')}>确定</button>
8、事件修饰符。需要使用 withModifiers 方法,接收两个参数,第一个参数是绑定的事件,第二个参数是需要使用的事件修饰符。
import { withModifiers, defineComponent, ref } from 'vue' const App = defineComponent({ setup() { const count = ref(0); const inc = () => { count.value++; }; return () => ( <div onClick={ withModifiers(inc, ['self']) }>{ count.value }</div> ); }, }) export default App
注意:Vue 模板中 ref 变量是可以直接解构的,但是在 jsx 中不行,需要添加 .value,比如上面的 { count.value }。
9、v-model 双向绑定。需要使用单大括号 {}。如果绑定属性则需要一个数组,第一个元素为绑定的值,第二个元素为绑定的属性。
// 绑定值 <input v-model="show" /> // vue <input v-model={show.value} /> // jsx // 绑定属性 <input v-model:prop="show" /> // vue <input v-model={[show.value,'prop']} /> // jsx // 修饰符写法 <input v-model:prop.trim="show" /> // vue <input v-model={[show.value,'prop',['trim']]} /> // jsx
10、slot 插槽。jsx/tsx 中无法使用 slot 标签,定义插槽方式一:通过 setup 函数的第一个参数 ctx 上下文对象的 slots 的属性,setup 函数默认接收两个参数:
如果解构了 props
对象,解构出的变量将会丢失响应性,因此推荐通过 props.xxx
的形式来使用其中的 props。如果确实需要解构 props
对象,或者需要将某个 prop 传到一个外部函数中并保持响应性,可以使用 toRefs() 和 toRef() 这两个工具函数:
import { toRefs, toRef } from 'vue' export default { setup(props) { // 将 `props` 转为一个其中全是 ref 的对象,然后解构 const { title } = toRefs(props) // `title` 是一个追踪着 `props.title` 的 ref console.log(title.value) // 或者,将 `props` 的单个属性转为一个 ref const title = toRef(props, 'title') } }
ctx 上下文对象是非响应式的,可以安全地解构:
export default { setup(props, { attrs, slots, emit, expose }) { ... } }
attrs 和 slots 都是响应式(有状态)的对象,它们总是会随着组件自身的更新而更新。这意味着你应当避免解构它们,并始终通过 attrs.x 或 slots.x 的形式使用其中的属性。此外,和 props 不同,attrs 和 slots 的属性都不是响应式的。如果想要基于 attrs 或 slots 的改变来执行副作用,那么应该在 onBeforeUpdate 生命周期钩子中编写相关逻辑。
expose 函数用于显式地限制该组件暴露出的属性,当父组件通过模板引用访问该组件的实例时,将仅能访问 expose 函数暴露出的内容:
export default { setup(props, { expose }) { // 让组件实例处于 “关闭状态” // 即不向父组件暴露任何东西 expose() const publicCount = ref(0) const privateCount = ref(0) // 有选择地暴露局部状态 expose({ count: publicCount }) } }
通过 ctx 上下文对象的 slots 的属性可以获取插槽对象后,就可以定义插槽了。
import { defineComponent } from 'vue' export default defineComponent({ setup(props, { slots }) { // 逻辑 return () => { return <p> <button>{ slots.test?.() }</button> <button>{ slots.default?.() }</button> </p> } }, }) // 在引用的组件中 <template #test>slot-test</template> <template #>slot-default</template>
定义插槽方式二:使用 renderSlot 函数。
import { renderSlot } from 'vue' <button> { renderSlot(slots, 'default') } </button>
而如果在 jsx 中使用插槽,可以直接通过标签属性 slot,或通过 v-slots 指令。
import HelloWorld from './HelloWorld' export default defineComponent({ setup() { return () => ( <div class={'box'}> <HelloWorld v-slots={{ title: () => { return <p>我是title插槽</p> }, default: () => { return <p>我是default插槽</p> } }} /> </div> ) } })
11、CSS Modules。引入局部样式,相当于 vue 组件中 c9ccee2e6ea535a969eb3f532ad9fe89
标签的 scoped 属性。
import styles from './index.module.scss' <div class={styles.wrap}></div>
The above is the detailed content of Detailed explanation of how to use JSX in Vue3+Vite. For more information, please follow other related articles on the PHP Chinese website!