zoukankan      html  css  js  c++  java
  • 学Vue,就要学会vue JSX(三)

    是时候使用JSX代替createElement

    接着上面的讲,当我们看到上面用createElement去实现组件,太麻烦了,别说工作效率提高了,就是那些嵌套可以嵌套正确就很赞了,所以我们需要用JSX去简化整个逻辑。当年我做项目的时候就遇到过这样的情况,嵌套太多,自己都快搞不明白了,在崩溃的边缘。

     methods: {
       $_handleInputUser(value) {
         this.formInline.user = value
       },
       $_handleChangeRegion(value) {
         this.formInline.region = value
       },
       $_handleSubmit() {}
     },
       /**
       *将 h 作为 createElement 的别名是 Vue 生态系统中的一个通用惯例,实际上也是 JSX 所要求的。从 Vue 的 Babel 插件的 3.4.0   *版本开始,我们会在以 ES2015 语法声明的含有 JSX 的任何方法和 getter 中 (不是函数或箭头函数中) 自动注入 
       *const h = this.$createElement,这样你就可以去掉 (h) 参数了。对于更早版本的插件,如果 h 在当前作用域中不可用,应用会抛错。
      */
     render(h) {
         return (
           <ElForm inline model={this.formInline} class="demo-form-inline">
             <ElFormItem label="审批人">
               <ElInput
                 value={this.formInline.user}
                 onInput={this.$_handleInputUser}
                 placeholder="审批人"
               ></ElInput>
             </ElFormItem>
             <ElFormItem label="活动区域">
               <ElSelect
                 value={this.formInline.region}
                 onChange={this.$_handleChangeRegion}
                 placeholder="活动区域"
               >
                 <ElOption label="区域一" value="shanghai"></ElOption>
                 <ElOption label="区域二" value="beijing"></ElOption>
               </ElSelect>
             </ElFormItem>
             <ElFormItem>
               <ElButton type="primarty" onClick={this.$_handleSubmit}>
                 查询
               </ElButton>
             </ElFormItem>
           </ElForm>
         )
       }

    看了上面的代码,大家其实会发现用JSXtemplate的语法都属于xml的写法,而且也比较像,但实质上还是有许多区别的,下面我将为大家一一分析

    没有v-model怎么办,还有其他指令可以用吗?

    当你选择使用JSX的时候,你就要做好和指令说拜拜的时候了,在JSX中, 你唯一可以使用的指令是v-show,除此之外,其他指令都是不可以使用的,有没有感到很慌,这就对了。不过呢,换一个角度思考,指令只是Vue在模板代码里面提供的语法糖,现在你已经可以写Js了,那些语法糖用Js都可以代替了。

    v-model

    v-modelVue提供的一个语法糖,它本质上是由 value属性(默认) + input事件(默认)组成的。所以,在JSX中,我们便可以回归本质,通过传递value属性并监听input事件来实现数据的双向绑定

     export default {
       data() {
         return {
           name: ''
         }
       },
       methods: {
         // 监听 onInput 事件进行赋值操作
         $_handleInput(e) {
           this.name = e.target.value
         }
       },
       render() {
         // 传递 value 属性 并监听 onInput事件
         return <input value={this.name} onInput={this.$_handleInput}></input>
       }
     }

    经我测试,在新版脚手架vue-cli4中,已经默认集成了对v-model的支持,大家可以直接使用`,如果你的项目比较老,也可以安装插件babel-plugin-jsx-v-model`来进行支持

    同样的,在JSX中,对于.sync也需要用属性+事件来实现,如下代码所示:

     export default {
       methods: {
         $_handleChangeVisible(value) {
           this.visible = value
         }
       },
       render() {
         return (
           <ElDialog
             title="测试.sync"
             visible={this.visible}
             on={{ 'update:visible': this.$_handleChangeVisible }}
           ></ElDialog>
         )
       }
     }

    v-if 与 v-for

    在模板代码里面我们通过v-for去遍历元素,通过v-if去判断是否渲染元素,在jsx中,对于v-for,你可以使用for循环,array.map来代替,对于v-if,可以使用if语句,三元表达式等来代替

    循环遍历列表

     const list = ['java', 'c++', 'javascript', 'c#', 'php']
     return (
       <ul>
       {list.map(item => {
        return <li>{item}</li>
       })}
       </ul>
     )

    使用条件判断

     const isGirl = false
     return isGirl ? <span>小妹,哥哥教你写Vue</span> : <span>鸟你干啥</span>

    v-bind

    在模板代码中,我们一般通过 v-bind:prop="value":prop="value"来给组件绑定属性,在JSX里面写法也类似

     render() {
       return <input value={this.name}></input>
     }

    v-html 与 v-text

    在说v-htmlv-text之前,我们需要先了解一下Vue中的属性,Vue中的属性一共分为三种,第一种是大家写bug时候最常用的props,即组件自定义的属性;第二种是attrs,是指在父作用域里面传入的,但并未在子组件内定义的属性。第三种比较特殊,是domProps,经小编不完全测试,在Vue中,domProps主要包含三个,分别是innerHTML,textContent/innerTextvalue

    • v-html: 在模板代码中,我们用v-html指令来更新元素的innerHTML内容,而在JSX里面,如果要操纵组件的innerHTML,就需要用到domProps

       export default {
         data() {
           return {
             content: '<div>这是Heo写的一篇新的文章</div>'
           }
         },
         render() {
           // v-html 指令在JSX的写法是 domPropsInnerHTML
           return <div domPropsInnerHTML={this.content}></div>
         }
       }
    • v-text: 看了上面的v-html,你是不是立即就想到了v-textJSX的写法domPropsInnerText,是的,你没有想错

       export default {
         data() {
           return {
             content: '这是Heo写的一篇新的文章的内容'
           }
         },
         render() {
           return <div domPropsInnerText={this.content}></div>
         }
       }

      但实际上我们不需要使用domPropsInnerText,而是将文本作为元素的子节点去使用即可

       <div>{this.content}</div>

    实际上,对于domProps,只有innerHTML才需要使用domPropsInnerHTML的写法,其他使用正常写法即可

    我还要监听事件呢

    监听事件与原生事件

    当我们开发一个组件之后,一般会通过this.$emit('change')的方式对外暴露事件,然后通过v-on:change的方式去监听事件,很遗憾,在JSX中你无法使用v-on指令,但你将解锁一个新的姿势

      render() {
         return <CustomSelect onChange={this.$_handleChange}></CustomSelect>
       }

     
     JSX`中,通过`on` + 事件名称的大驼峰写法来监听,比如事件`icon-click`,在`JSX`中写为`onIconClick

    有时候我们希望可以监听一个组件根元素上面的原生事件,这时候会用到.native修饰符,有点绝望啊,修饰符也是不能用了,但好在也有替代方案,如下代码

      render() {
         // 监听下拉框根元素的click事件
         return <CustomSelect nativeOnClick={this.$_handleClick}></CustomSelect>
       }

    监听原生事件的规则与普通事件是一样的,只需要将前面的on替换为nativeOn

    除了上面的监听事件的方式之外,我们还可以使用对象的方式去监听事件

       render() {
         return (
           <ElInput
             value={this.content}
             on={{
               focus: this.$_handleFocus,
               input: this.$_handleInput
             }}
             nativeOn={{
               click: this.$_handleClick
             }}
           ></ElInput>
         )
       }

    事件修饰符

    和指令一样,除了个别的之外,大部分的事件修饰符都无法在JSX中使用,这时候你肯定已经习惯了,肯定有替代方案的。

    • .stop : 阻止事件冒泡,在JSX中使用event.stopPropagation()来代替

    • .prevent:阻止默认行为,在JSX中使用event.preventDefault() 来代替

    • .self:只当事件是从侦听器绑定的元素本身触发时才触发回调,使用下面的条件判断进行代替

       if (event.target !== event.currentTarget){
         return
       }
    • .enterkeyCode: 在特定键触发时才触发回调

       if(event.keyCode === 13) {
         // 执行逻辑
       }

    除了上面这些修饰符之外,尤大大为了照顾我们这群CV仔,还是做了一点优化的,对于.once,.capture,.passive,.capture.once,尤大大提供了前缀语法帮助我们简化代码

      render() {
         return (
           <div
             on={{
               // 相当于 :click.capture
               '!click': this.$_handleClick,
               // 相当于 :input.once
               '~input': this.$_handleInput,
               // 相当于 :mousedown.passive
               '&mousedown': this.$_handleMouseDown,
               // 相当于 :mouseup.capture.once
               '~!mouseup': this.$_handleMouseUp
             }}
           ></div>
         )
       }

    对了,还有插槽

    插槽就是子组件中提供给父组件使用的一个占位符,插槽分为默认插槽,具名插槽和作用域插槽,下面我依次为您带来每种在JSX中的用法与如何去定义插槽。

    默认插槽

    • 使用默认插槽

    使用element-uiDialog时,弹框内容就使用了默认插槽,在JSX中使用默认插槽的用法与普通插槽的用法基本是一致的,如下代码所示:

      render() {
         return (
           <ElDialog title="弹框标题" visible={this.visible}>
             {/*这里就是默认插槽*/}
             <div>这里是弹框内容</div>
           </ElDialog>
         )
       }
    • 自定义默认插槽

      Vue的实例this上面有一个属性$slots,这个上面就挂载了一个这个组件内部的所有插槽,使用this.$slots.default就可以将默认插槽加入到组件内部

       export default {
         props: {
           visible: {
             type: Boolean,
             default: false
           }
         },
         render() {
           return (
             <div class="custom-dialog" vShow={this.visible}>
               {/**通过this.$slots.default定义默认插槽*/}
               {this.$slots.default}
             </div>
           )
         }
       }

    具名插槽

    • 使用具名插槽

      有时候我们一个组件需要多个插槽,这时候就需要为每一个插槽起一个名字,比如element-ui的弹框可以定义底部按钮区的内容,就是用了名字为footer的插槽

      render() {
         return (
           <ElDialog title="弹框标题" visible={this.visible}>
             <div>这里是弹框内容</div>
             {/** 具名插槽 */}
             <template slot="footer">
               <ElButton>确定</ElButton>
               <ElButton>取消</ElButton>
             </template>
           </ElDialog>
         )
       }
    • 自定义具名插槽

    在上节自定义默认插槽时提到了$slots,对于默认插槽使用this.$slots.default,而对于具名插槽,可以使用this.$slots.footer进行自定义

     render() {
         return (
           <div class="custom-dialog" vShow={this.visible}>
             {this.$slots.default}
             {/**自定义具名插槽*/}
             <div class="custom-dialog__foolter">{this.$slots.footer}</div>
           </div>
         )
       }

    作用域插槽

    • 使用作用域插槽

      有时让插槽内容能够访问子组件中才有的数据是很有用的,这时候就需要用到作用域插槽,在JSX中,因为没有v-slot指令,所以作用域插槽的使用方式就与模板代码里面的方式有所不同了。比如在element-ui中,我们使用el-table的时候可以自定义表格单元格的内容,这时候就需要用到作用域插槽

       data() {
           return {
             data: [
               {
                 name: 'Heo'
               }
             ]
           }
         },
         render() {
           return (
             {/**scopedSlots即作用域插槽,default为默认插槽,如果是具名插槽,将default该为对应插槽名称即可*/}
             <ElTable data={this.data}>
               <ElTableColumn
                 label="姓名"
                 scopedSlots={{
                   default: ({ row }) => {
                     return <div style="color:red;">{row.name}</div>
                   }
                 }}
               ></ElTableColumn>
             </ElTable>
           )
         }
    • 自定义作用域插槽

      使用作用域插槽不同,定义作用域插槽也与模板代码里面有所不同。加入我们自定义了一个列表项组件,用户希望可以自定义列表项标题,这时候就需要将列表的数据通过作用域插槽传出来。

       render() {
           const { data } = this
           // 获取标题作用域插槽
           const titleSlot = this.$scopedSlots.title
           return (
             <div class="item">
               {/** 如果有标题插槽,则使用标题插槽,否则使用默认标题 */}
               {titleSlot ? titleSlot(data) : <span>{data.title}</span>}
             </div>
           )
         }

    ok。vue JSX 的重点就已经讲完了。下面一篇文章来讲一下注意的地方和总结。大家觉得对你有帮助的话可以给我点个赞哦,推荐给更多的人看。

  • 相关阅读:
    百度云 shadow-root 内的video 倍速播放
    记一次临摹百度登录界面
    es6 函数的扩展
    01-let和const.html
    selenium 禁止加载图片 css js
    前端小知识(11)--js数组方法
    前端小知识(10)--js深拷贝
    算法系列(1)--广度优先遍历和深度优先遍历
    前端小知识(9)--选择器
    前端小知识(8)--BFC
  • 原文地址:https://www.cnblogs.com/coderhf/p/13261483.html
Copyright © 2011-2022 走看看