草庐IT

Vue中JSX的基本用法

CRMEB众邦科技 2023-03-28 原文

基本用法

首先需要约定一下,使用JSX组件命名采用首字母大写的驼峰命名方式,样式可以少的可以直接基于vue-styled-components写在同一个文件中,复杂的建议放在单独的_Styles.js_文件中,当然也可以不采用CSS-IN-JS的方式,使用Less/Sass来写,然后在文件中import进来。

下面是一个通用的骨架:

import styled from 'vue-styled-components'

const Container = styled.div`
heigth: 100%;
`

const Dashboard = {
name: 'Dashboard',

render() {
return (
<Container>内容</Container>
)
}
}

export default Dashboard

插值

在JSX中使用单个括号来绑定文本插值

<span>Message: {this.messsage}</span>
<!-- 类似于v-html -->
<div domPropsInnerHTML={this.dangerHtml}/>
<!-- v-model -->
<el-input v-model={this.vm.name} />

在jsx中不需要把​​v-model​​分成事件绑定和赋值二部分分开来写,因为有相应的babel插件来专门处理。

样式

在JSX中可以直接使用​​class="xx"​​​来指定样式类,内联样式可以直接写成​​style="xxx"​

<div class="btn btn-default" style="font-size: 12px;">Button</div>

<!-- 动态指定 -->
<div class={`btn btn-${this.isDefault ? 'default' : ''}`}></div>
<div class={{'btn-default': this.isDefault, 'btn-primary': this.isPrimary}}></div>
<div style={{color: 'red', fontSize: '14px'}}></div>

遍历

在JSX中没有​​v-for​​​和​​v-if​​等指令的存在,这些全部需要采用Js的方式来实现

{/* 类似于v-if */}
{this.withTitle && <Title />}

{/* 类似于v-if 加 v-else */}
{this.isSubTitle ? <SubTitle /> : <Title />}

{/* 类似于v-for */}
{this.options.map(option => {
<div>{option.title}</div>
})}

事件绑定

事件绑定需要在事件名称前端加上​​on​​​前缀,原生事件添加​​nativeOn​

<!-- 对应@click -->
<el-buton onClick={this.handleClick}>Click me</el-buton>
<!-- 对应@click.native -->
<el-button nativeOnClick={this.handleClick}>Native click</el-button>
<!-- 传递参数 -->
<el-button onClick={e => this.handleClick(this.id)}>Click and pass data</el-button>

注意:如果需要给事件处理函数传参数,需要使用箭头函数来实现。如果不使用箭头函数那么接收的将会是事件的对象​​event​​属性。

高级部分

在Vue中基于jsx也可以把组件拆分成一个个小的函数式组件,但是有一个限制是必需有一个外层的包裹元素,不能直接写类似:

const Demo = () => (
<li>One</li>
<li>Two</li>
)

必需写成:

const Demo = () => (
<div>
<li>One</li>
<li>Two</li>
</div>
)

而在React中可以使用空标签​​<></>​​​和​​<react.Fragment></react.Fragment>​​​来实现包裹元素,这里的空标签其实只是​​react.Fragment​​的一个语法糖。同时在React 16中直接支持返回数组的形式:

const Demo = () => [
<li>One</li>
<li>Two</li>
]

那么在Vue中就只能通过遍历来实现类似的功能,大体思路就是把数据先定义好数据然后直接一个​​map​​生成,当然如果说元素的标签是不同类型的那就需要额外添加标识来判断了。

{
data() {
return {
options: ['one', 'two']
}
},

render() {
const LiItem = () => this.options.map(option => <li>{option}</li>)

return (
<div>
<ul>
<LiItem />
</ul>
</div>
)
}
}

事件修饰符

在基础部分简单介绍了事件的绑定用法,这里主要是补充一下事件修饰符的写法。

在模板语法中Vue提供了很多事件修饰符来快速处理事件的冒泡、捕获、事件触发频率、按键识别等。可以直接查看官方文档的​​事件&按键修饰符​​部分,这里把相关内容原样搬运过来:

修饰符

前缀

​.passive​

​&​

​.capture​

​!​

​.once​

​~​

​.capture.once​​​或​​.once.capture​

​~!​

使用方式如下:

<el-button {...{
'!click': this.doThisInCapturingMode,
'!keyup': this.doThisOnce,
'~!mouseover': this.doThisOnceInCapturingMode
}}>Click Me!</el-button>

下面给出的事件修饰符是需要在事件处理函数中写出对应的等价操作

修饰符

处理函数中的等价操作

​.stop​

​event.stopPropagation()​

​.prevent​

​event.preventDefault()​

​.self​

​if (event.target !== event.currentTarget) return​

按键: ​​.enter​​​, ​​.13​

​if (event.keyCode !== 13) return​​​ (对于别的按键修饰符来说,可将 ​​13​​​ 改为​​另一个按键码​​)

修饰键: ​​.ctrl​​​, ​​.alt​​​, ​​.shift​​​, ​​.meta​

​if (!event.ctrlKey) return​​​ (将 ​​ctrlKey​​​ 分别修改为 ​​altKey​​​、​​shiftKey​​​ 或者 ​​metaKey​​)

下面是在事件处理函数中使用修饰符的例子:

methods: {
keyup(e) {
// 对应`.self`
if (e.target !== e.currentTarget) return

// 对应 `.enter`, `.13`
if (!e.shiftKey || e.keyCode !== 13) return

// 对应 `.stop`
e.stopPropagation()

// 对应 `.prevent`
e.preventDefault()

// ...
}
}

ref和refInFor

在Vue中​​ref​​​被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 ​​$refs​​ 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件。

注意

  • 因为 ref 本身是作为渲染结果被创建的,在初始渲染的时候你不能访问它们 - 它们还不存在
  • ​$refs​​不是响应式的,因此你不应该试图用它在模板中做数据绑定。
当 ​​v-for​​ 用于元素或组件的时候,引用信息将是包含 DOM 节点或组件实例的数组。

假如在jsx中想要引用遍历元素或组件的时候,例如:

const LiArray = () => this.options.map(option => (
<li ref="li" key={option}>{option}</li>
))

会发现从​​this.$refs.li​​​中获取的并不是期望的数组值,这个时候就需要使用​​refInFor​​​属性,并置为​​true​​​来达到在模板中​​v-for​​​中使用​​ref​​的效果:

const LiArray = () => this.options.map(option => (
<li ref="li" refInFor={true} key={option}>{option}</li>
))

插槽(v-slot)

在jsx中可以使用​​this.$slots​​来访问静态插槽的内容。

注意:在Vue 2.6.x版本后废弃了​​slot​​​和​​slot-scope​​​,在模板中统一使用新的统一语法​​v-slot​​​指令。​​v-slot​​​只能用于Vue组件和​​template​​标签。

<div class="page-header__title">
{this.$slots.title ? this.$slots.title : this.title}
</div>

等价于模板的

<div class="page-header__title">
<slot name="title">{{ title }}</slot>
</div>

在Vue官方文档中提到:**父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。**因此像下面的示例是无法正常工作的

<current-user>
{{ user.firstName }}
</current-user>

在​​<current-user>​​​组件中可以访问到​​user​​属性,但是提供的内容却是在父组件渲染的。如果想要达到期望的效果,这个时候就需要使用作用域插槽了。下面是改写后的代码,更多知识点可以直接查看官方文档的​​作用域插槽​​。

<!-- current-user组件定义部分 -->
<span>
<slot v-bind:user="user">
{{ user.lastName }}
</slot>
</span>

<!-- current-user 使用 -->
<current-user>
<template v-slot:default="slotProps">
{{ slotProps.user.firstName }}
</template>
</current-user>

上面的示例其实就是官方的示例,这里需要说明的是,其实在Vue中所谓的作用域插槽功能类似于React中的Render Props的概念,只不过在React中我们更多时候不仅提供了属性,还提供了操作方法。但是在Vue中更多的是提供数据供父作用域渲染展示,当然我们也可以把方法提供出去,例如:

<template>
<div>
<slot v-bind:injectedProps="slotProps">
{{ user.lastName }}
</slot>
</div>
</template>

<script>
export default {
data() {
return {
user: {
firstName: 'snow',
lastName: 'wolf'
}
}
},

computed: {
slotProps() {
return {
user: this.user,
logFullName: this.logFullName
}
}
},

methods: {
logFullName() {
console.log(`${this.firstName} ${this.lastName}`)
}
}
}
</script>

在父组件中使用:

<current-user>
<template v-slot:default="{ injectedProps }">
<div>{{ injectedProps.user.firstName }}</div>
<el-button @click="injectedProps.logFullName">Log Full Name</el-button>
</template>
</current-user>

在上面的代码中我们实际上使用解构的方式来取得​​injectedProps​​​,基于解构的特性还可以重命名属性名,在​​prop​​​为​​undefined​​的时候指定初始值。

<current-user v-slot="{ user = { firstName: 'Guest' } }">
{{ user.firstName }}
</current-user>

如果组件只有一个默认的插槽还可以使用缩写语法,将​​v-slot:default="slotProps"​​​写成​​v-slot="slotProps"​​​,命名插槽写成​​v-slot:user="slotProps"​​,如果想要动态插槽名还可以写成​​v-slot:[dynamicSlotName]​​,此外具名插槽同样也有缩写语法,例如 ​​v-slot:header​​​可以被重写为​​#header​

上面介绍了很多插槽相关的知识点足已说明其在开发过程中的重要性。说了很多在模板中如何定义和使用作用域插槽,现在进入正题如何在jsx中同样使用呢?

// current-user components
{
data() {
return {
user: {
firstName: 'snow',
lastName: 'wolf'
}
}
},

computed: {
slotProps() {
return {
user: this.user,
logFullName: this.logFullName
}
}
},

methods: {
logFullName() {
console.log(`${this.firstName} ${this.lastName}`)
}
},

render() {
return (
<div>
{this.$scopedSlots.subTitle({
injectedProps: this.slotProps
})}
</div>
)
}
}

然后在父组件中以jsx使用:

<current-user {...{
scopedSlots: {
subTitle: ({ injectedProps }) => (
<div>
<h3>injectedProps.user</h3>
<el-button onClick={injectedProps.logFullName}>Log Full Name</el-button>
</div>
)
}
}}></current-user>

指令

这里需要注意的是在jsx中所有Vue内置的指令除了​​v-show​​​以外都不支持,需要使用一些等价方式来实现,比如​​v-if​​​使用三目运算表达式、​​v-for​​​使用​​array.map()​​等。

对于自定义的指令可以使用​​v-name={value}​​​的语法来写,需要注意的是指令的参数、修饰符此种方式并不支持。以官方文档指令部分给出的示例​​v-focus​​使用为例,介绍二种解决办法:

1 直接使用对象传递所有指令属性

<input type="text" v-focus={{ value: true }} />

2 使用原始的vnode指令数据格式

{
directives:{
focus: {
inserted: function(el) {
el.focus()
}
}
},

render() {
const directives = [
{ name: 'focus', value: true }
]

return (
<div>
<input type="text" {...{ directives }} />
</div>
)
}
}

过滤器

过滤器其实在开发过程中用得倒是不多,因为更多时候可以通过计算属性来对数据做一些转换和筛选。这里只是简单提及一下并没有什么可以深究的知识点。

在模板中的用法如下:

<!-- 在双花括号中 -->
{{ message | capitalize }}

<!-- 在 `v-bind` 中 -->
<div v-bind:id="rawId | formatId"></div>

在jsx中使用方法为:

<div>{this.$options.filters('formatDate')('2019-07-01')}</div>

注意:由于Vue全局的过滤器只用于模板中,如果需要用于组件的方法中,可以把过滤器方法单独抽离出一个公共Js文件,然后引入组件中,然后用于方法中。

有关Vue中JSX的基本用法的更多相关文章

  1. Unity 热更新技术 | (三) Lua语言基本介绍及下载安装 - 2

    ?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------

  2. 计算机毕业设计ssm+vue基本微信小程序的小学生兴趣延时班预约小程序 - 2

    项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU

  3. ruby-on-rails - 使用 HTTParty 的非常基本的 Rails 4.1 API 调用 - 2

    Rails相对较新。我正在尝试调用一个API,它应该向我返回一个唯一的URL。我的应用程序中捆绑了HTTParty。我已经创建了一个UniqueNumberController,并且我已经阅读了几个HTTParty指南,直到我想要什么,但也许我只是有点迷路,真的不知道该怎么做。基本上,我需要做的就是调用API,获取它返回的URL,然后将该URL插入到用户的数据库中。谁能给我指出正确的方向或与我分享一些代码? 最佳答案 假设API为JSON格式并返回如下数据:{"url":"http://example.com/unique-url"

  4. ruby-on-rails - Rails 基本 Base64 身份验证 - 2

    我正在尝试复制此GETcurl请求:curl-D--XGET-H"Authorization:BasicdGVzdEB0YXByZXNlYXJjaC5jb206NGMzMTg2Mjg4YWUyM2ZkOTY2MWNiNWRmY2NlMTkzMGU="-H"Content-Type:application/json"http://staging.example.com/api/v1/campaigns在Ruby中,通过电子邮件+apikey生成身份验证:auth="Basic"+Base64::encode64("test@example.com:4c3186288ae23fd9661c

  5. ruby - 有人可以解释一下在 Ruby 中注入(inject)的真实、通俗易懂的用法吗? - 2

    我正在学习Ruby,遇到了inject。我正处于理解它的风口浪尖,但当我是那种需要真实世界的例子来学习一些东西的人时。我遇到的最常见的例子是人们使用inject来添加一个(1..10)范围的总和,我不太关心这个。这是一个任意的例子。在实际程序中我会用它做什么?我正在学习,所以我可以继续使用Rails,但我不必有一个以Web为中心的示例。我只需要一些我可以全神贯注的目标。谢谢大家。 最佳答案 inject有时可以通过它的“其他”名称reduce更好地理解。它是一个对Enumerable进行操作(迭代一次)并返回单个值的函数。它有许多有

  6. ruby - 使用法拉第上传文件 - 2

    我在尝试使用Faraday将文件上传到网络服务时遇到问题。我的代码:conn=Faraday.new('http://myapi')do|f|f.request:multipartendpayload={:file=>Faraday::UploadIO.new('...','image/jpeg')}conn.post('/',payload)尝试发布后似乎没有任何反应。当我检查响应时this是我所看到的:#:post,:body=>#,#,@opts={}>,#],@index=0>>,#>],@ios=[#,#,@opts={}>,#],@index=0>,#],@index=0>

  7. ruby - rspec: raise_error 用法来匹配错误信息 - 2

    我使用raise(ConfigurationError.new(msg))引发错误我试着用rspec测试一下:expect{Base.configuration.username}.toraise_error(ConfigurationError,message)但这行不通。我该如何测试呢?目标是匹配message。 最佳答案 您可以使用正则表达式匹配错误消息:it{expect{Foo.bar}.toraise_error(NoMethodError,/private/)}这将检查NoMethodError是否由privateme

  8. (附源码)vue3.0+.NET6实现聊天室(实时聊天SignalR) - 2

    参考文章搭建文章gitte源码在线体验可以注册两个号来测试演示图:一.整体介绍  介绍SignalR一种通讯模型Hub(中心模型,或者叫集线器模型),调用这个模型写好的方法,去发送消息。  内容有:    ①:Hub模型的方法介绍    ②:服务器端代码介绍    ③:前端vue3安装并调用后端方法    ④:聊天室样例整体流程:1、进入网站->调用连接SignalR的方法2、与好友发送消息->调用SignalR的自定义方法 前端通过,signalR内置方法.invoke()  去请求接口3、监听接受方法(渲染消息)通过new signalR.HubConnectionBuilder().on

  9. Simulink方法总结和避坑指南(一)——Simulink入门与基本调试方法 - 2

    文章目录一、项目场景二、基本模块原理与调试方法分析——信源部分:三、信号处理部分和显示部分:四、基本的通信链路搭建:四、特殊模块:interpretedMATLABfunction:五、总结和坑点提醒一、项目场景  最近一个任务是使用simulink搭建一个MIMO串扰消除的链路,并用实际收到的数据进行测试,在搭建的过程中也遇到了不少的问题(当然这比vivado里面的debug好不知道多少倍)。准备趁着这个机会,先以一个很基本的通信链路对simulink基础和相关的debug方法进行总结。  在本篇中,主要记录simulink的基本原理和基本的SISO通信传输链路(QPSK方式),计划在下篇记

  10. 【ChatGPT】ChatGPT 的 N 种用法 - 2

    目录ChatGPT简介技术原理应用未来发展ChatGPT的10 种用法ChatGPT简介ChatGPT是一种基于深度学习的大型语言模型,由OpenAI公司开发。技术原理GPT是GenerativePre-trainedTransformer的缩写,意为生成式预训练变压器。它的技术原理是使用了一个基于注意力机制的变压器(Trans

随机推荐