乐趣区

关于vue.js:Vue-中-JSX-的基本用法

根本用法
首先须要约定一下,应用 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 文件,而后引入组件中,而后用于办法中。

源码附件曾经打包好上传到百度云了,大家自行下载即可~

链接: https://pan.baidu.com/s/14G-b…
提取码: yu27
百度云链接不稳固,随时可能会生效,大家放松保留哈。

如果百度云链接生效了的话,请留言通知我,我看到后会及时更新~

开源地址
码云地址:
http://github.crmeb.net/u/defu

Github 地址:
http://github.crmeb.net/u/defu

退出移动版