前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Vue JSX、自定义 v-model

Vue JSX、自定义 v-model

原创
作者头像
Krry
修改2020-07-17 09:58:58
4.5K1
修改2020-07-17 09:58:58
举报
文章被收录于专栏:KrryblogKrryblog

博客地址:https://ainyi.com/92

最初用到 JSX,就是做这个博客的时候。iview 表格组件,不支持像 element 那样直接写 html 代码渲染,只能通过 render 函数渲染,也就是 JSX 语法

这个说起来不陌生,JSX 是 react 框架的老本行了,玩 react 的同学肯定对这个也玩的很溜(最近在公司做的某些项目也是 react)

那我还是记录一下在 Vue JSX 的使用吧

JSX 定义

JSX 是一种 JavaScript 的语法扩展,多运用于 React 架构中。==JSX = Javascript + XML==,即在 Javascript 里面写 XML,即具备 Javascript 的灵活性,又有 html 的语义化和直观性

应用场景

有人说,Vue 的模板语法简单易上手,实现的功能也几乎足够。JSX 不好上手,写起来代码量也多,用来干啥呢

那你就忽略了 JavaScript 的灵活性了

函数式组件

简单说一下函数式组件

函数式组件就是函数是组件。使用过 React 的同学,应该不会对函数式组件感到陌生

函数式组件,我们可以理解为==没有内部状态==,==没有生命周期钩子函数==,==没有 this==(不需要实例化的组件)

在日常开发中,经常会开发一些纯展示性的业务组件,比如一些详情页面,列表界面等,它们有一个共同的特点是只需要将外部传入的数据进行展现,不需要有内部状态,不需要在生命周期钩子函数里面做处理,这时候你就可以考虑使用函数式组件

代码语言:txt
复制
export default {
  // 通过配置 functional 属性指定组件为函数式组件
  functional: true,
  // 组件接收的外部属性
  props: {
    avatar: {
      type: String
    }
  },
  /**
   * 渲染函数
   * @param {*} h
   * @param {*} context 函数式组件没有 this, props, slots 等,都在 context 上面挂着
   */
  render(h, context) {
    const { props } = context
    if (props.avatar) {
      return <img src={props.avatar}></img>
    }
    return <img src="default-avatar.png"></img>
  }
}

使用函数式组件的原因:

  1. 最主要最关键的原因是函数式组件不需要实例化,无状态,没有生命周期,所以渲染性能要好于普通组件
  2. 函数式组件结构比较简单,代码结构更清晰

函数式组件与普通组件的区别

  1. 函数式组件需要在组件上声明==functional==
  2. 函数式组件不需要实例化,所以没有 this,==this==通过==render==函数的第二个参数来代替
  3. 函数式组件没有生命周期钩子函数,不能使用计算属性、watch 等等
  4. 函数式组件不能通过 $emit 对外暴露事件,调用事件只能通过==context.listeners.click==的方式调用外部传入的事件
  5. 因为函数式组件是没有实例化的,所以在外部通过==ref==去引用组件时,实际引用的是 HTMLElement
  6. 函数式组件的==props==可以不用显示声明,所以没有在==props==里面声明的属性都会被自动隐式解析为 prop,而普通组件所有未声明的属性都被解析到 $attrs 里面,并自动挂载到组件根元素上面(可以通过 inheritAttrs 属性禁止)

模板语法声明函数式组件

在 Vue2.5 之前,使用函数式组件只能通过 JSX 的方式,在之后可以通过==模板语法==来声明函数式组件

代码语言:txt
复制
<!-- 在template 上面添加 functional属性 -->
<template functional>
  <img :src="props.avatar ? props.avatar : 'default-avatar.png'" />
</template>
<!-- 上面第 6 条,可以省略声明 props -->

了解 createElement

学习 JSX 之前,先了解 createElement

字面意思,==创建元素== 大名鼎鼎的==虚拟DOM==应该都知道吧,就是它的返回值 => 插播一个以前写过的==VNode==传送门:virtual DOM

关于 createElement 方法,有三个参数:

  1. 第一个参数主要用于提供 dom 的 html 内容,类型可以是字符串、对象或函数。比如 “div” 就是创建一个 div 标签
  2. 第二个参数(类型是对象)主要用于设置这个 dom 的一些样式、属性、传的组件的参数、绑定事件之类,具体可以参考 官方文档 里这一小节的说明
  3. 第三个参数(类型是数组,数组元素类型是 VNode)主要用于说是该节点下有其他结点的话,就放在这里

使用例子:

代码语言:txt
复制
export default {
 methods: {
    $_handleChangeUser(value) {
      this.formInline.user = value
    }
  },
  render(h) {
    return h(
      'ElForm',
      {
        props: {
          inline: true,
          model: this.formInline
        },
        staticClass: 'demo-form-inline'
      },
      [
        h(
          'ElFormItem',
          {
            props: {
              label: '用户名'
            }
          },
          [
            h('ElInput', {
              props: {
                value: this.formInline.user
              },
              attrs: {
                placeholder: '请输入用户名'
              },
              on: {
                input: this.$_handleChangeUser
              }
            })
          ]
        )
      ]
    )
  }
}

看起来写法十分复杂,若页面上这么多元素,频繁使用 createElement 方法难免代码臃肿,这时就应该使用 JSX 代替 createElement 了

JSX

我们再来用 JSX 语法重新实现上面的代码

代码语言:txt
复制
methods: {
  $_handleInputUser(value) {
    this.formInline.user = value
  }
},
render(h) {
  return (
    <el-form inline model={this.formInline} class="demo-form-inline">
      <el-form-item label="用户名">
        <el-input
          value={this.formInline.user}
          onInput={this.$_handleInputUser}
          placeholder="请输入用户名"
        ></el-input>
      </el-form-item>
    </el-form>
  )
}

跟 react 一模一样了

将 h 作为 createElement 的别名 是 Vue 生态系统中的一个通用惯例,实际上也是 JSX 所要求的

从 Vue 的 Babel 插件的 3.4.0 版本开始,我们会在以 ES2015 语法声明的含有 JSX 的任何方法和 getter 中 (不是函数或箭头函数中) 自动注入==const h = this.$createElement==,这样就可以去掉 (h) 参数了。对于更早版本的插件,如果 h 在当前作用域中不可用,应用会报错

Vue JSX 中指令的使用

我们使用 Vue 模板语法,指令用的爽歪歪,像 v-model, v-if, v-for, @, 插槽等等

但是,这些都在 JSX 中无法使用。那么如何实现相同的功能呢

注意:新版 vue-cli4 中,已经默认集成了 JSX 语法对 v-model 的支持,可以直接使用 <input v-model={this.value}> 如果你的项目比较老,也可以安装插件 babel-plugin-jsx-v-model 来进行支持

自定义 v-model

v-model 是 Vue 提供的一个语法糖,它本质上是由 value 属性 + input 事件组成的(都是原生的默认属性)

所以在 JSX 中,我们可以通过传递 value 属性并监听 input 事件来实现数据的双向绑定

代码语言:txt
复制
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>
  }
}

封装组件如下:

子组件

代码语言:txt
复制
<template>
  <div>
    <input :value="value" @change="$_handleChange" />
  </div>
</template>

<script>
export default {
  props: {
    value: {
      type: String,
      default: ''
    }
  },
  data() {
    return {}
  },
  methods: {
    $_handleChange(e) {
      this.$emit('input', e.target.value)
    }
  }
}
</script>

父组件

代码语言:txt
复制
<template>
  <div class="home">
    <krry-input v-model="say"></krry-input>
  </div>
</template>

<script>
export default {
  name: 'Home',
  components: {
    KrryInput: () => import('@/components/KrryInput')
  },
  data() {
    return {
      say: 'haha'
    }
  }
}
</script>

再次重申:新版 vue-cli4 中,已经默认集成了 JSX 语法对 v-model 的支持,可以直接使用 <input v-model={this.value}>

el-form 的 :model 属性

注意 el-form 的 :model 属性,在 JSX 中是这样写的 props={{ model: this.data }},比较特别

代码语言:txt
复制
<el-form
  ref="form"
  labelWidth="140px"
  rules={this.rules}
  props={{ model: this.data }}>
  <el-form-item label="券码编号: ">
    <el-input v-model={this.data.voucherCode}></el-input>
  </el-form-item>
<el-form>

v-if | v-for

这两个就比较常见,搞 react 都知道,v-if 可以使用三元表达式,true or false 来渲染组件;v-for 就使用 map 方法来实现

代码语言:txt
复制
const list = ['宫', '商', '角', '徵', '羽']
return (
  <ul>
    { list.map(ele => <li>{ele}</li>) }
  </ul>
)

v-html | v-text

在 JSX 里面,如果要设置 dom 元素的 innerHTML,就用到 domProps

代码语言:txt
复制
export default {
  data() {
    return {
      content: '<div>这是我的自定义的 html 元素</div>'
    }
  },
  render() {
    // v-html 指令在 JSX 的写法是 domPropsInnerHTML
    return <div domPropsInnerHTML={this.content}></div>
  }
}

v-text 就没啥好说的了,<div domPropsInnerText={this.content}></div>

还不如直接使用 <div>{this.content}</div>

监听事件

监听事件想到用 onChange, onClick

需要注意的是,传参数不能使用 onClick={this.removePhone(params)},这样子会每次 render 的时候都会自动执行一次方法

应该使用 bind,或者箭头函数来传参

代码语言:txt
复制
<button type="button" onClick={this.handleClick.bind(this, 11)}></button>
<button type="button" onClick={() => this.handleClick(11)}></button>

除此之外,还可以使用对象的方式去监听事件

代码语言:txt
复制
render() {
  return (
    <el-input
      value={this.content}
      on={{
        focus: this.$_handleFocus,
        input: this.$_handleInput
      }}
      nativeOn={{
        click: this.$_handleClick
      }}
    ></el-input>
  )
}

使用范围

不仅仅在 render 函数里面使用 JSX,而且还可以在 methods 里面返回 JSX,然后在 render 函数里面调用这个方法

JSX 还可以直接赋值给变量

代码语言:txt
复制
methods: {
  $_renderFooter() {
    return (
      <div>
        <el-button>确定</el-button>
        <el-button>取消</el-button>
      </div>
    )
  }
},
render() {
  const buttons = this.$_renderFooter()
  return (
    <el-dialog visible={this.visible}>
      <div>弹窗内容</div>
      <template slot="footer">{buttons}</template>
    </el-dialog>
  )
}

博客地址:https://ainyi.com/92

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • JSX 定义
  • 应用场景
    • 函数式组件
    • 了解 createElement
    • JSX
    • Vue JSX 中指令的使用
      • 自定义 v-model
        • el-form 的 :model 属性
          • v-if | v-for
            • v-html | v-text
            • 监听事件
            • 使用范围
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档