当前位置:   article > 正文

详细教会你在vue中写jsx_vue jsx

vue jsx

目录

前言:

一、用render函数写一个页面:

二、在render函数注册事件

三、vue指令在render函数是怎么代替的:

1、v-if

2、v-show

3、v-for:

4、v-model:

5、.sync

四、render中插槽的使用

1、默认插槽

 2、具名插槽

 3、作用域插槽

五、传参、事件绑定、行内属性的对象写法(深入数据对象):

六、最后结合之前的例子试一下:

先到这里吧,后续再更新!


前言:

近几年都比较流行vue3+tsx相信react开发应该还是很了解jsx语法的,但是很多vue初中级开发还是很多人不会使用jsx,不知道怎么写。接下来慢慢教你哈(项目中使用的是vue2+jsx,因为主题是讲在vue中使用jsx)!

一、用render函数写一个页面:

首先vue中有个render函数,他只支持xml的形式返回dom结构。开发中需要使用jsx语法就需要对项目文件进行改造:


1、写页面不能用.vue当文件后缀了,需要改成jsx,如果是ts就是tsx。


下面是一个home.jsx:

  1. export default {
  2. name:'home',
  3. components:{},
  4. props:{},
  5. data(){
  6. return {
  7. info:{
  8. age:18
  9. }
  10. }
  11. },
  12. computed:{},
  13. watch:{},
  14. mounted(){},
  15. methods:{},
  16. render() {
  17. return <div>我是小明,我今年{this.info.age}岁</div>
  18. }
  19. }

2、使用.vue当文件后缀也是可以的,但需要在script中加入 lang="tsx" (使用javaScript就是jsx) 

  1. <script lang="tsx">
  2. export default {
  3. name:'home',
  4. components:{},
  5. props:{},
  6. data(){
  7. return {
  8. info:{
  9. age:18
  10. }
  11. }
  12. },
  13. computed:{},
  14. watch:{},
  15. mounted(){},
  16. methods:{},
  17. render() {
  18. return <div>我是小明,我今年{this.info.age}岁</div>
  19. }
  20. }
  21. </script>

页面呈现是这样的:

其实在vue中写jsx并没有多难,只是语法稍微有点不同而已。比如上面的例子,home.jsx文件后缀名从.vue变成了.jsx。内部把 template 的结构搬到了,render函数中。当然在render函数中写 template模版 结构和大致写法都一样,但是还是有些地方需要注意的。

上面的例子中.vue中变量是这样写的{{info.age}},jsx中双花括号变成了单个,并且变量需要附带this。

二、在render函数注册事件

在render函数注册事件和 template 中的 v-on:click||@click不同,偏向原声写法如click事件onClick={tins.click}、input事件onInput={this.input},写法如下:

  1. export default {
  2. name: 'home',
  3. components: {},
  4. props: {},
  5. data() {
  6. return {
  7. info: {
  8. age: 18,
  9. gender: ''
  10. },
  11. }
  12. },
  13. computed: {},
  14. watch: {},
  15. mounted() {
  16. },
  17. methods: {
  18. Gender() {
  19. this.info.gender = '男';
  20. }
  21. },
  22. render() {
  23. return <div className="home">
  24. <div>我是小明,我今年{this.info.age}岁</div>
  25. <div>我是{this.info.gender}性</div>
  26. <button onClick={this.Gender}>查询我的性别</button>
  27. </div>
  28. }
  29. }

页面如下:

三、vue指令在render函数是怎么代替的:

在render函数中没有指令这个东西了,比如v-if,v-show等这些都是自定义指令。在vue中写v-if或者v-show是这样的,如下:

1、v-if

v-if其实就是控制{}内的代码返回值。返回dom或者返回空

  1. export default {
  2. name: 'home',
  3. components: {},
  4. props: {},
  5. data() {
  6. return {
  7. info: {
  8. age: 18,
  9. gender: ''
  10. },
  11. }
  12. },
  13. computed: {},
  14. watch: {},
  15. mounted() {
  16. },
  17. methods: {
  18. getGender() {
  19. this.info.gender = '男';
  20. },
  21. genderDom() {
  22. return this.info.gender ? <div>我是{this.info.gender}性</div> : ''
  23. }
  24. },
  25. render() {
  26. return <div className="home">
  27. <div>我是小明,我今年{this.info.age}岁</div>
  28. {/* 三元表达写法 */}
  29. {
  30. this.info.gender ? <div>我是{this.info.gender}性</div> : ''
  31. }
  32. {/* 也可以用&&判断写 */}
  33. {
  34. this.info.gender && <div>我是{this.info.gender}性</div>
  35. }
  36. {/* 函数返回写法 */}
  37. {
  38. this.genderDom()
  39. }
  40. {/* 错误写法,在render不能直接使用if else */}
  41. {/* {
  42. if(this.info.gender){
  43. return <div>我是{this.info.gender}性</div>
  44. }else{
  45. return ''
  46. }
  47. } */}
  48. <button onClick={this.getGender}>查询我的性别</button>
  49. </div>
  50. }
  51. }

2、v-show

vue中的v-show大家都应该知道它只是控制样式display的none||block,那知道这点其实就很简单了:

  1. export default {
  2. name: 'home',
  3. components: {},
  4. props: {},
  5. data() {
  6. return {
  7. info: {
  8. age: 18,
  9. gender: ''
  10. },
  11. }
  12. },
  13. computed: {},
  14. watch: {},
  15. mounted() {
  16. },
  17. methods: {
  18. getGender() {
  19. this.info.gender = '男';
  20. },
  21. genderDom() {
  22. return this.info.gender ? <div>我是{this.info.gender}性</div> : ''
  23. }
  24. },
  25. render() {
  26. return <div className="home">
  27. <div>我是小明,我今年{this.info.age}岁</div>
  28. {/* 控制性别这个div的样式即可 */}
  29. <div style={{ display: this.info.gender ? 'block' : 'none' }}>我是
  30. {this.info.gender}性</div>
  31. <button onClick={this.getGender}>查询我的性别</button>
  32. </div>
  33. }
  34. }

注:上面代码中style={{ display: this.info.gender ? 'block' : 'none' }} 可以这样写?style={obj};obj={display: this.info.gender ? 'block' : 'none'},这样是不是就理解了,里面只是一个对象,还是单个花括号放变量的!

3、v-for:

jsx中实现v-for,只是用.map代替了而已:

map只是jsx实现v-for手段之一,简单的来说任何返回改造后数组的函数都可以实现v-for

  1. // this.arr = [1,2,3,4,5];
  2. // map
  3. <div>
  4. {this.arr.map((item,index)=><div key={index}>{item}</div>)}
  5. </div>
  6. // reduce
  7. <div>
  8. {this.arr.reduce((arr,index)=>{
  9. return [...arr,<div key={index}>{item}</div>]
  10. },[]))}
  11. </div>

4、v-model:

说到v-model,这个你就要理解vue中v-model其实只是一个语法糖,它就是:value,@input 两个方法组合起来的而已。那么在render中写法如下:

index.jsx

  1. import hobby from './component/hobby';
  2. export default {
  3. name: 'home',
  4. components: { hobby },
  5. props: {},
  6. data() {
  7. return {
  8. info: {
  9. age: 18,
  10. gender: '',
  11. hobby: '我是一个没有爱好的木头人!'
  12. },
  13. }
  14. },
  15. computed: {},
  16. watch: {},
  17. mounted() {
  18. },
  19. methods: {
  20. getGender() {
  21. this.info.gender = '男';
  22. },
  23. genderDom() {
  24. return this.info.gender ? <div>我是{this.info.gender}性</div> : ''
  25. }
  26. },
  27. render() {
  28. return <div className="home">
  29. <div>我是小明,我今年{this.info.age}岁</div>
  30. {/* 控制性别这个div的样式即可 */}
  31. <div style={{ display: this.info.gender ? 'block' : 'none' }}>我是
  32. {this.info.gender}性</div>
  33. <button onClick={this.getGender}>查询我的性别</button>
  34. <hobby value={this.info.hobby} onInput={(value) => { this.info.hobby =
  35. value }} />
  36. </div>
  37. }
  38. }

index.jsx中引入的子组件,hobby.jsx :

  1. export default {
  2. name: 'hobby',
  3. components: {},
  4. props: {
  5. value: {
  6. type: String,
  7. debugger: '我是一个没有爱好的木头人!'
  8. }
  9. },
  10. data() {
  11. return {
  12. }
  13. },
  14. computed: {},
  15. watch: {},
  16. mounted() {
  17. },
  18. methods: {
  19. },
  20. render() {
  21. return <div className="hobby">
  22. 我的爱好是:{this.value}
  23. <input value={this.value} onInput={(e) => { this.$emit('input',
  24. e.target.value); }} />
  25. </div>
  26. }
  27. }

好麻烦我就不每次截页面的图了。这个你们自己拷贝的代码去试试看就知道了! 

hobby.jsx中的input 其实就是一个v-model的实现,然后在看一下index.jsx中在hobby组件上直接写

v-model,其实就是hobby接受了个value,然后再用$emit一个input事件去修改v-model的值。当然你也可以用vue的model去改变v-model的value,和input。使用自定义名字(因为开发中可能存在value或者input被其它参数使用了),这里就不多介绍啦。

最后如果你觉得v-model写起来好麻烦,想直接在render中使用v-model。那么也不是不行,

去安装一个 babel-plugin-jsx-v-model 依赖。然后在项目根目录找到babel.config.js,加入

就可以直接使用了!

5、.sync

在template中使用.sync是这样的:visible.sync="dialogVisible",但是在render中使用.sync是如下这样的

父组件index.jsx:

  1. import hobby from './component/hobby';
  2. import child from './component/child';
  3. export default {
  4. name: 'home',
  5. components: { hobby, child },
  6. props: {},
  7. data() {
  8. return {
  9. info: {
  10. age: 18,
  11. gender: '',
  12. hobby: '我是一个没有爱好的木头人!'
  13. },
  14. childData: "父亲传给child的数据",
  15. }
  16. },
  17. computed: {},
  18. watch: {},
  19. mounted() {
  20. },
  21. methods: {
  22. getGender() {
  23. this.info.gender = '男';
  24. },
  25. genderDom() {
  26. return this.info.gender ? <div>我是{this.info.gender}性</div> : ''
  27. }
  28. },
  29. render() {
  30. return <div className="home">
  31. <div>我是小明,我今年{this.info.age}岁</div>
  32. {/* 控制性别这个div的样式即可 */}
  33. <div style={{ display: this.info.gender ? 'block' : 'none' }}>我是
  34. {this.info.gender}性</div>
  35. <button onClick={this.getGender}>查询我的性别</button>
  36. {/* <hobby value={this.info.hobby} onInput={(value) => {
  37. this.info.hobby = value }} /> */}
  38. <hobby value={this.info.hobby} onInput={(value) => { this.info.hobby =
  39. value }} />
  40. <div>模拟.sycn</div>
  41. {this.childData}
  42. <child
  43. {...{
  44. props: {
  45. value: this.childData
  46. },
  47. on: {
  48. 'update:value': (val) => {
  49. console.log(val)
  50. this.childData = val;
  51. },
  52. }
  53. }}
  54. />
  55. </div>
  56. }
  57. }

简单来说,有可能会有这种情况,就是你写了个jsx的组件,但是你的同事他不会jsx。但是他要使用你写的jsx组件,然后用.sync,那你同事是这样写的<child value.sync='value' />。然后你就不知道怎么接受了,并且去改变value.sync='value'中的value?其实.sycn和v-model一样只是个语法糖而已,它是由.sycn前面的变量名,也就是bind一个value(名字自定义的)和 on一个‘update:value’名字的方法而已。

四、render中插槽的使用

1、默认插槽

默认插槽只是简写(不用自定义插槽名称)的具名插槽,默认名称为default;

在 template 中使用默认插槽:

  1. // 父组件
  2. <template>
  3. <child>
  4. 我是插入的内容
  5. </child>
  6. </template>
  7. // 子组件 child
  8. <template>
  9. <div>
  10. <slot />
  11. </div>
  12. </template>

在 render 中使用默认插槽: 

  1. // 父组件 写法1
  2. render(){
  3. return <div>
  4. <child>
  5. 默认插槽
  6. </child>
  7. </div>
  8. }
  9. // 父组件也可以这样写 写法2
  10. render(){
  11. return <div>
  12. <child {
  13. ...{
  14. scopedSlots: {
  15. default:()=>'默认插槽'
  16. }
  17. }
  18. }/>
  19. </div>
  20. }
  21. // child 子组件
  22. render(){
  23. return <div>
  24. {this.$scopedSlots.default()} // 写法1、写法2 都可以在这里显示,但是写法2会覆盖写法1
  25. {this.$slots.default} // this.$slots.default 是一个数组,所以直接使用展示
  26. </div>
  27. }

 2、具名插槽

        同默认插槽写法基本一样,只需吧对接key改成对应的名称即可。(默认插槽其实也是具名插槽,只是它的名称叫default,为了简写所以不传名字而已)

  1. // 父组件 写法1
  2. render(){
  3. return <div>
  4. <child>
  5. <div slot="soltName">
  6. 具有名字的插槽1
  7. </div>
  8. </child>
  9. </div>
  10. }
  11. // 父组件也可以这样写 写法2
  12. render(){
  13. return <div>
  14. <child {
  15. ...{
  16. scopedSlots: {
  17. soltName:()=>'具有名字的插槽2'
  18. }
  19. }
  20. }/>
  21. </div>
  22. }
  23. // child 子组件
  24. render(){
  25. return <div>
  26. {this.$scopedSlots.soltName()} // 写法1、写法2 都可以在这里显示,但是写法2会覆盖写法1
  27. {this.$slots.soltName} // this.$slots.soltName 是一个数组,所以直接使用展示
  28. </div>
  29. }

 3、作用域插槽

  1. // 父组件
  2. render(){
  3. return <div>
  4. <child {
  5. ...{
  6. scopedSlots: {
  7. soltName:(scope)=><div>
  8. child对我说:{scope}
  9. </div>
  10. }
  11. }
  12. }/>
  13. </div>
  14. }
  15. // child 子组件
  16. render(){
  17. return <div>
  18. {this.$scopedSlots.soltName('我是child,我要告诉你我的真心话!')}
  19. </div>
  20. }

从上面代码可以发现,
 插槽对象有两种:scopedSlots、slots。
scopedSlots 具备 默认、具名、作用域;支持深入对象写法;使用插槽时表现为函数返回值也是数组,但是需要注意的时深入对象在和普通写法中重名的情况,深入对象插槽优先级别更高
slots 具备 默认、具名;不支持深入对象写法;使用插槽时直接就是vnode数组;

五、传参、事件绑定、行内属性的对象写法(深入数据对象):

相信很多人可能看不懂之前例子中这种穿参数的方式,其实你需要了解dom节点的props、attrs、on...这些属性的区别即可。这只是一个写法的不同:

  1. // template 中 你使用组件可能是这样写的
  2. <child :value='value' @click="click" style="width=100px" calss='class'/>
  3. // 上面给 child组件传了一个value,绑定了一个点击事件,加了一个行内样式,绑定了一个样式
  4. // jsx中可以这样写
  5. <child {...{
  6. props:{
  7. value:value,
  8. },
  9. on:{
  10. click:click
  11. },
  12. attrs:{
  13. style="width=100px",
  14. class="class"
  15. }
  16. }}/>
  17. // 这样写是不是看的更明白了?
  18. const obj = {
  19. props:{
  20. value:value,
  21. },
  22. on:{
  23. click:click
  24. },
  25. attrs:{
  26. style="width=100px",
  27. class="class"
  28. }
  29. }
  30. <child {...obj}/>

 注:

on:就是绑定的事件,比如你需要绑定input事件只需要在on 对象中添加一个值key:value的形式,key是你的事件名称、value是你绑定的function。

props:其实就是子组件接受的props,和on差不多也是key:value的形式。

attrs:就是需要绑定在当前dom上的行内属性,比如class、style、type、name、id等,可以在控制台中看见。

借鉴了一下官方的介绍,可以看看: 

  1. {
  2. // 与 `v-bind:class` 的 API 相同,
  3. // 接受一个字符串、对象或字符串和对象组成的数组
  4. 'class': {
  5. foo: true,
  6. bar: false
  7. },
  8. // 与 `v-bind:style` 的 API 相同,
  9. // 接受一个字符串、对象,或对象组成的数组
  10. style: {
  11. color: 'red',
  12. fontSize: '14px'
  13. },
  14. // 普通的 HTML attribute
  15. attrs: {
  16. id: 'foo'
  17. },
  18. // 组件 prop
  19. props: {
  20. myProp: 'bar'
  21. },
  22. // DOM property
  23. domProps: {
  24. innerHTML: 'baz'
  25. },
  26. // 事件监听器在 `on` 内,
  27. // 但不再支持如 `v-on:keyup.enter` 这样的修饰器。
  28. // 需要在处理函数中手动检查 keyCode。
  29. on: {
  30. click: this.clickHandler
  31. },
  32. // 仅用于组件,用于监听原生事件,而不是组件内部使用
  33. // `vm.$emit` 触发的事件。
  34. nativeOn: {
  35. click: this.nativeClickHandler
  36. },
  37. // 自定义指令。注意,你无法对 `binding` 中的 `oldValue`
  38. // 赋值,因为 Vue 已经自动为你进行了同步。
  39. directives: [
  40. {
  41. name: 'my-custom-directive',
  42. value: '2',
  43. expression: '1 + 1',
  44. arg: 'foo',
  45. modifiers: {
  46. bar: true
  47. }
  48. }
  49. ],
  50. // 作用域插槽的格式为
  51. // { name: props => VNode | Array<VNode> }
  52. scopedSlots: {
  53. default: props => createElement('span', props.text)
  54. },
  55. // 如果组件是其它组件的子组件,需为插槽指定名称
  56. slot: 'name-of-slot',
  57. // 其它特殊顶层 property
  58. key: 'myKey',
  59. ref: 'myRef',
  60. // 如果你在渲染函数中给多个元素都应用了相同的 ref 名,
  61. // 那么 `$refs.myRef` 会变成一个数组。
  62. refInFor: true
  63. }

六、最后结合之前的例子试一下:

index.jsx

  1. import child from './component/child';
  2. export default {
  3. name: 'Test',
  4. components: { child },
  5. props: {},
  6. data() {
  7. return {
  8. age: 17,
  9. arr: [{ name: '小明', age: 16 }, { name: '小明妈妈', age: 40 }, { name: '小明爸爸', age: 46 }]
  10. }
  11. },
  12. computed: {
  13. setOptions() {
  14. return {
  15. //插槽属性
  16. scopedSlots: {
  17. default: (scope) => <div>我是默认插槽,{this.showScope(scope)}
  18. </div>,
  19. slotsName: (scope) => <div>我是具名插槽,我的名字叫slotsName,
  20. {this.showScope(scope)}</div>,
  21. },
  22. props: {
  23. age: this.age,
  24. },
  25. attrs: {
  26. style: 'width:100%;height:200px;background-color:red'
  27. },
  28. on: {
  29. ageAdd: () => { this.age++ },
  30. input: (count) => { this.age = count }
  31. }
  32. }
  33. }
  34. },
  35. watch: {},
  36. mounted() {
  37. },
  38. methods: {
  39. showScope(scope) {
  40. return `子组件传给我的参数是:${scope}`
  41. }
  42. },
  43. render() {
  44. return <div class="Test">
  45. <div>父组件</div>
  46. 我的年龄是:{this.age}
  47. <div>子组建</div>
  48. <child {...this.setOptions} />
  49. <div>小明全家</div>
  50. <ul>
  51. {
  52. this.arr.map((item, index) => <div key={index}>
  53. {item.name}:{item.age}
  54. </div>)
  55. }
  56. </ul>
  57. {/* <child {...this.setOptions} v-model={this.age}/> */}
  58. </div>
  59. }
  60. }

child.jsx

  1. export default {
  2. name: 'child',
  3. components: {},
  4. // model: {
  5. // prop: "inputValue",
  6. // event: "up",
  7. // },
  8. props: ['age'],
  9. data() {
  10. return {
  11. }
  12. },
  13. computed: {},
  14. watch: {},
  15. mounted() {
  16. console.log(this.$attrs, this.$listeners)
  17. },
  18. methods: {
  19. },
  20. render() {
  21. return <div class="child">
  22. <button onClick={() => { this.$emit('ageAdd') }}>老一岁</button>
  23. <div>
  24. 修改年纪:
  25. <input value={this.age} onInput={(e) => { this.$emit('input',
  26. e.target.value) }} />
  27. {/* <input value={this.$attrs.inputValue} onInput={(e) => {
  28. this.$emit('up', e.target.value) }} /> */}
  29. </div>
  30. <div>插槽</div>
  31. {this.$scopedSlots.default&&this.$scopedSlots.default(666)}
  32. {this.$scopedSlots.slotsName&&this.$scopedSlots.slotsName(789)}
  33. </div>
  34. }
  35. }

 可以去试试看,方法了解开发中需要灵活运用,逻辑清晰。

其实官方介绍的就挺详细的渲染函数 & JSX — Vue.js

先到这里吧,后续再更新!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/494395
推荐阅读
相关标签
  

闽ICP备14008679号