目录
  • 前言:
  • 一、用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结构。但是写页面不能用.vue当文件后缀了,需要改成jsx,如果是ts就是tsx。
        下面是一个home.jsx:

        export default {
            name:'home',
            components:{},
            props:{},
            data(){
                return {
                    info:{
                        age:18
                    }
                }
            },
            computed:{},
            watch:{},
            mounted(){},
            methods:{},
            render() {
                return <div>我是小明,我今年{this.info.age}岁</div>
            }
        }

        页面呈现是这样的:

        其实在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},写法如下:

        export default {
            name: 'home',
            components: {},
            props: {},
            data() {
                return {
                    info: {
                        age: 18,
                        gender: ''
                    },
                }
            },
            computed: {},
            watch: {},
            mounted() {
            },
            methods: {
                Gender() {
                    this.info.gender = '男';
                }
            },
            render() {
                return <div className="home">
                    <div>我是小明,我今年{this.info.age}岁</div>
                    <div>我是{this.info.gender}性</div>
                    <button onClick={this.Gender}>查询我的性别</button>
                </div>
            }
        }

        页面如下:

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

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

        1、v-if

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

        export default {
            name: 'home',
            components: {},
            props: {},
            data() {
                return {
                    info: {
                        age: 18,
                        gender: ''
                    },
                }
            },
            computed: {},
            watch: {},
            mounted() {
            },
            methods: {
                getGender() {
                    this.info.gender = '男';
                },
                genderDom() {
                    return this.info.gender ? <div>我是{this.info.gender}性</div> : ''
                }
            },
            render() {
                return <div className="home">
                    <div>我是小明,我今年{this.info.age}岁</div>
                    {/* 三元表达写法 */}
                    {
                        this.info.gender ? <div>我是{this.info.gender}性</div> : ''
                    }
                    {/* 也可以用&&判断写 */}
                    {
                        this.info.gender && <div>我是{this.info.gender}性</div>
                    }
                    {/* 函数返回写法 */}
                    {
                        this.genderDom()
                    }
                    {/* 错误写法,在render不能直接使用if else */}
                    {/* {
                        if(this.info.gender){
                            return <div>我是{this.info.gender}性</div>
                        }else{
                            return ''
                        }
                    } */}
                    <button onClick={this.getGender}>查询我的性别</button>
                </div>
            }
        }

        2、v-show

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

        export default {
            name: 'home',
            components: {},
            props: {},
            data() {
                return {
                    info: {
                        age: 18,
                        gender: ''
                    },
                }
            },
            computed: {},
            watch: {},
            mounted() {
            },
            methods: {
                getGender() {
                    this.info.gender = '男';
                },
                genderDom() {
                    return this.info.gender ? <div>我是{this.info.gender}性</div> : ''
                }
            },
            render() {
                return <div className="home">
                    <div>我是小明,我今年{this.info.age}岁</div>
                    {/* 控制性别这个div的样式即可 */}
                    <div style={{ display: this.info.gender ? 'block' : 'none' }}>我是                
                    {this.info.gender}性</div>
                    <button onClick={this.getGender}>查询我的性别</button>
                </div>
            }
        }

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

        3、v-for:

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

        // this.arr = [1,2,3,4,5];
        <div>
            {this.arr.map((item,index)=><div key={index}>{item}</div>)}
        </div>

        4、v-model:

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

        index.jsx

        import hobby from './component/hobby';
        export default {
            name: 'home',
            components: { hobby },
            props: {},
            data() {
                return {
                    info: {
                        age: 18,
                        gender: '',
                        hobby: '我是一个没有爱好的木头人!'
                    },
                }
            },
            computed: {},
            watch: {},
            mounted() {
            },
            methods: {
                getGender() {
                    this.info.gender = '男';
                },
                genderDom() {
                    return this.info.gender ? <div>我是{this.info.gender}性</div> : ''
                }
            },
            render() {
                return <div className="home">
                    <div>我是小明,我今年{this.info.age}岁</div>
                    {/* 控制性别这个div的样式即可 */}
                    <div style={{ display: this.info.gender ? 'block' : 'none' }}>我是        
                    {this.info.gender}性</div>
                    <button onClick={this.getGender}>查询我的性别</button>
                    <hobby value={this.info.hobby} onInput={(value) => { this.info.hobby = 
                     value }} />
                </div>
            }
        }

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

        export default {
            name: 'hobby',
            components: {},
            props: {
                value: {
                    type: String,
                    debugger: '我是一个没有爱好的木头人!'
                }
            },
            data() {
                return {
                }
            },
            computed: {},
            watch: {},
            mounted() {
            },
            methods: {
            },
            render() {
                return <div className="hobby">
                    我的爱好是:{this.value}
                    <input value={this.value} onInput={(e) => { this.$emit('input',             
                    e.target.value); }} />
                </div>
            }
        }

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

        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:

        import hobby from './component/hobby';
        import child from './component/child';
        export default {
            name: 'home',
            components: { hobby, child },
            props: {},
            data() {
                return {
                    info: {
                        age: 18,
                        gender: '',
                        hobby: '我是一个没有爱好的木头人!'
                    },
                    childData: "父亲传给child的数据",
                }
            },
            computed: {},
            watch: {},
            mounted() {
            },
            methods: {
                getGender() {
                    this.info.gender = '男';
                },
                genderDom() {
                    return this.info.gender ? <div>我是{this.info.gender}性</div> : ''
                }
            },
            render() {
                return <div className="home">
                    <div>我是小明,我今年{this.info.age}岁</div>
                    {/* 控制性别这个div的样式即可 */}
                    <div style={{ display: this.info.gender ? 'block' : 'none' }}>我是 
                    {this.info.gender}性</div>
                    <button onClick={this.getGender}>查询我的性别</button>
                    {/* <hobby value={this.info.hobby} onInput={(value) => {             
                     this.info.hobby = value }} /> */}
                    <hobby value={this.info.hobby} onInput={(value) => { this.info.hobby = 
                     value }} />
                    <div>模拟.sycn</div>
                    {this.childData}
                    <child
                        {...{
                            props: {
                                value: this.childData
                            },
                            on: {
                                'update:value': (val) => {
                                    console.log(val)
                                    this.childData = val;
                                },
                            }
                        }}
                    />
                </div>
            }
        }

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

        四、render中插槽的使用

        1、默认插槽

        在 template 中使用默认插槽:

        // 父组件
        <template>
            <child>
            我是插入的内容
            </child>
        </template>
        // 子组件 child
        <template>
            <div>
                <slot />
            </div>
        </template>
         

        在 render 中使用默认插槽:

        // 父组件
        render(){
            return <div>
                <child>
                    默认插槽
                </child>
            </div>
        }
        // 父组件也可以这样写
        render(){
            return <div>
                <child {
                    ...{
                        scopedSlots: {
                            default:()=>'默认插槽'
                        }
                    }
                }/>
            </div>
        }
        // child 子组件
        render(){
            return <div>
                {this.$scopedSlots.default()}
            </div>
        }

        2、具名插槽

        render(){
            return <div>
                <child {
                    ...{
                        scopedSlots: {
                            soltName:()=>'具名插槽'
                        }
                    }
                }/>
            </div>
        }
        // child 子组件
        render(){
            return <div>
                {this.$scopedSlots.soltName()}
            </div>
        }

        3、作用域插槽

        // 父组件
        render(){
            return <div>
                <child {
                    ...{
                        scopedSlots: {
                            soltName:(scope)=><div>
                                child对我说:{scope}
                            </div>
                        }
                    }
                }/>
            </div>
        }
        // child 子组件
        render(){
            return <div>
                {this.$scopedSlots.soltName('我是child,我要告诉你我的真心话!')}
            </div>
        }

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

        相信很多人可能看不懂之前例子中

        这种穿参数的方式,其实你需要了解dom节点的props、attrs、on...这些属性的区别即可。这只是一个写法的不同:

        // template 中 你使用组件可能是这样写的
        <child :value='value' @click="click" style="width=100px" calss='class'/>
        // 上面给 child组件传了一个value,绑定了一个点击事件,加了一个行内样式,绑定了一个样式
        // jsx中可以这样写
        <child {...{
            props:{
                value:value,
            },
            on:{
                click:click
            },
            attrs:{
                style="width=100px",
                class="class"
            }
        }}/>
        // 这样写是不是看的更明白了?
        const obj = {
            props:{
                value:value,
            },
            on:{
                click:click
            },
            attrs:{
                style="width=100px",
                class="class"
            }
        }
        <child {...obj}/>

        注:

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

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

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

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

        {
          // 与 `v-bind:class` 的 API 相同,
          // 接受一个字符串、对象或字符串和对象组成的数组
          'class': {
            foo: true,
            bar: false
          },
          // 与 `v-bind:style` 的 API 相同,
          // 接受一个字符串、对象,或对象组成的数组
          style: {
            color: 'red',
            fontSize: '14px'
          },
          // 普通的 HTML attribute
          attrs: {
            id: 'foo'
          },
          // 组件 prop
          props: {
            myProp: 'bar'
          },
          // DOM property
          domProps: {
            innerHTML: 'baz'
          },
          // 事件监听器在 `on` 内,
          // 但不再支持如 `v-on:keyup.enter` 这样的修饰器。
          // 需要在处理函数中手动检查 keyCode。
          on: {
            click: this.clickHandler
          },
          // 仅用于组件,用于监听原生事件,而不是组件内部使用
          // `vm.$emit` 触发的事件。
          nativeOn: {
            click: this.nativeClickHandler
          },
          // 自定义指令。注意,你无法对 `binding` 中的 `oldValue`
          // 赋值,因为 Vue 已经自动为你进行了同步。
          directives: [
            {
              name: 'my-custom-directive',
              value: '2',
              expression: '1 + 1',
              arg: 'foo',
              modifiers: {
                bar: true
              }
            }
          ],
          // 作用域插槽的格式为
          // { name: props => VNode | Array<VNode> }
          scopedSlots: {
            default: props => createElement('span', props.text)
          },
          // 如果组件是其它组件的子组件,需为插槽指定名称
          slot: 'name-of-slot',
          // 其它特殊顶层 property
          key: 'myKey',
          ref: 'myRef',
          // 如果你在渲染函数中给多个元素都应用了相同的 ref 名,
          // 那么 `$refs.myRef` 会变成一个数组。
          refInFor: true
        }

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

        index.jsx

        import child from './component/child';
        export default {
            name: 'Test',
            components: { child },
            props: {},
            data() {
                return {
                    age: 17,
                    arr: [{ name: '小明', age: 16 }, { name: '小明妈妈', age: 40 }, { name: '小明爸爸', age: 46 }]
                }
            },
            computed: {
                setOptions() {
                    return {
                        //插槽属性
                        scopedSlots: {
                            default: (scope) => <div>我是默认插槽,{this.showScope(scope)} 
                            </div>,
                            slotsName: (scope) => <div>我是具名插槽,我的名字叫slotsName, 
                            {this.showScope(scope)}</div>,
                        },
                        props: {
                            age: this.age,
                        },
                        attrs: {
                            style: 'width:100%;height:200px;background-color:red'
                        },
                        on: {
                            ageAdd: () => { this.age++ },
                            input: (count) => { this.age = count }
                        }
                    }
                }
            },
            watch: {},
            mounted() {
            },
            methods: {
                showScope(scope) {
                    return `子组件传给我的参数是:${scope}`
                }
            },
            render() {
                return <div class="Test">
                    <div>父组件</div>
                    我的年龄是:{this.age}
                    <div>子组建</div>
                    <child {...this.setOptions} />
                    <div>小明全家</div>
                    <ul>
                        {
                            this.arr.map((item, index) => <div key={index}>
                                {item.name}:{item.age}
                            </div>)
                        }
                    </ul>
                    {/* <child {...this.setOptions} v-model={this.age}/> */}
                </div>
            }
        }

        child.jsx

        export default {
            name: 'child',
            components: {},
            // model: {
            //     prop: "inputValue",
            //     event: "up",
            // },
            props: ['age'],
            data() {
                return {
                }
            },
            computed: {},
            watch: {},
            mounted() {
                console.log(this.$attrs, this.$listeners)
            },
            methods: {
            },
            render() {
                return <div class="child">
                    <button onClick={() => { this.$emit('ageAdd') }}>老一岁</button>
                    <div>
                        修改年纪:
                        <input value={this.age} onInput={(e) => { this.$emit('input',     
                         e.target.value) }} />
                        {/* <input value={this.$attrs.inputValue} onInput={(e) => { 
                         this.$emit('up', e.target.value) }} /> */}
                    </div>
                    <div>插槽</div>
                    {this.$scopedSlots.default&&this.$scopedSlots.default(666)}
                    {this.$scopedSlots.slotsName&&this.$scopedSlots.slotsName(789)}
                </div>
            }
        }

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

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

        总结

        到此这篇关于在vue中写jsx的文章就介绍到这了,更多相关vue中写jsx内容请搜索本网站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本网站!

        您可能感兴趣的文章:
        • 在vue中使用jsx语法的使用方法
        • Vue 3.0中jsx语法的使用
        • 详解Vue如何支持JSX语法
        • vue组件jsx语法的具体使用
        • 在vue中写jsx的几种方式
        • 如何在 Vue 中使用 JSX
        • vue中正确使用jsx语法的姿势分享
        • Vue中jsx不完全应用指南小结