trionfo1993

trionfo1993 查看完整档案

上海编辑上海海洋大学  |  信息管理与信息系统 编辑上海信桦普信息科技有限公司  |  前端工程师 编辑 www.jianshu.com/u/6e96ca25886f 编辑
编辑

Hello world

个人动态

trionfo1993 赞了文章 · 2020-03-08

vue的jsx写法记录

[toc]

通过本文, 你可以学到一些vuejsx的语法。

vue更加推荐使用模板开发组件,但是在一些基础组件开发中,为了获取js的完全编程能力,不可避免需要使用一些jsx语法,而官方vue jsxvue特有的语法糖这方面的文档特别少, 本文记录一些本人在开发过程中使用jsx的经验和思考。

整体上来看,由于vuecreateElementreactcreateElement有区别,导致jsx的写法也有一些区别.但整体上还是符合react的jsx,react jsx进阶的语法。

如果需要了解vue jsx特殊写法的原理,可以阅读babel-plugin-transform-vue-jsx , 本文不做探讨。

data写法

jsx本质上是createElement的语法糖,最终会被编译器转为createElement函数.当在jsx的标签中使用{ ...obj }时, obj将会编译为createElement的第二个参数.

vuecreateElement跟react的createElement函数第二个参数意义是不一样的.在vue中,第二个参数是 data对象, 而react第二个参数是props。所以本人将这种方式称为data写法

如在vue中需要设置动态属性时:

const props={
  name: 'joyer',
},

<my-button {...{
  props:props,
}}></my-button>

当不知道模板中某个vue语法怎么用jsx中实现时,可以先转换为createElementdata对象,然后使用{...data}写在jsx标签上(本文重点).

如官方推荐原生dom属性的jsx写法:

<button domPropsType="submit"><button>

采用data写法为:

<button { ...{
  domProps: {
    type: 'submit',
  }, 
}}><button>

该方式不够优雅,如果官方有更加优雅的语法糖,推荐使用官方推荐。如果某个语法,官方没有案例,该方式就可以作为最终选择。 并且通过这种方式,createElement中所有的特性都可以用于jsx的开发了。

下文中所有的写法, 都可以使用data写法。

v-model的写法

官网中v-model写法不可行。

模板中写法为:

<el-input v-model.trim="inputValue"/>

jsx写法需要为:

<el-input vModel_trim={inputValue}/>
// 或者使用
<el-input 
 value={this.inputValue}
 on-input={val => this.inputValue = val.trim()}/>

v-for

模板中的写法:

<el-tag
 v-for="(item, index) in content"
 :key="index"
 type="success"
 >
    {{item.name}}
</el-tag>

jsx的写法:

{
  this.content.map((item, index) = >{
    return (<el-tag
      key={ index }
      type="success">{ item.name }</el-tag>);
  })
}

事件 & 按键修饰符

官方的写法

<input vOn:click_stop_prevent="newTodoText" />

一些编辑器会提示语法错误(因为reactjsx不允许这样写),推荐使用下面的写法

<input
 nativeOn-keyup={arg => arg.keyCode === 13 && this.fetch()}
 on-click={event => {event.stopPropagation();event.preventDefault();this.click()} }/>

修饰符需要自己在代码中实现。或者可以使用修饰符简写,对照官网的语法, jsx写法为:

<input {...{
    on: {
     '!click': () => this.doThisInCapturingMode,
    '~keyup': () => this.doThisOnce,
    '~!mouseover': () => this.doThisOnceInCapturingMode
    }
}} />

事件处理都采用了箭头函数, 跟react一样, 需要处理this绑定问题,可以使用bind绑定,

`on-click={this.click.bind(this, args) }`

不能直接赋值函数on-click={this.click}

高阶组件中的v-on="$listeners"v-bind="$attrs"

在高阶组件中, 一般都会使用v-on="$listeners"v-bind="$attrs",但在官方文档没有说明jsx如何实现,只有createElement中说明了实现:

return createElement('div', {
    props: {
      ...$attrs,
      otherProp: value,
    },
    on: {
      ...$listeners,
      click() {
      },
    }
},this.$slots.default])

参照data写法, jsx实现为:

const data = {
  props: {
     ...$attrs,
     otherProp: value,
  },
  on: {
     ...$listeners,
     click() {
     },
  }
}

<button { ...data }><button>

对于$attrs$listeners可以有更加灵活的用法。如要实现elemet-ui中一个可以快速布局el-form-item高阶组件,将el-form-itemel-col的结合:

render(h) {
 // 拆分出作用于col和form-item上的属性
 const colAttrs = {};
 const itemAtts = {};
 this.$attrs.forEach((attrName) => {
    // 这里使用了lodash
    if (_.startsWith(attrName, `col-`)) {
         colAttrs[attrName.replace(`col-`, '')] = this.$attrs[attrName];
         return;
    }
    itemAtts[attrName] = this.$attrs[attrName];
 });
 return (<el-col {
    ...{
       props: this.colAttrs,
    }
 }> 
    <el-form-item {
        ...{
            props: this.itemAtts,
        }
    }></el-form-item>
 </el-col>);
}

该高阶组件可以传递两种类型的属性, 带col-开头的属性,作用于el-col上面, 其他属性作用于el-form-item组件上。

如果需要标签属性透传,将当前组件的所有attrs传递给内部组件(内部组件也用v-bind="$attrs"),还需设置attrs值。
如高阶组件my-button:

<el-button v-bind="$attrs" type="primary">
 <slot></slot>
</el-button>

高阶组件high-button:

render(h) {
 return (<my-button { ...{
  props: this.attrs,
  attrs: this.$attrs,
 } }><my-button>);
}

通过设置attrshigh-button接收到的所有标签设置传递给my-button中。如果不这样做, 那么my-button中将接收不到任何属性设置,因为只传递props,在high-button组件中对于没有匹配high-buttonprops声明的标签属性都会被丢弃。

slot写法

默认插槽模板写法:

<button>
    <slot></slot>
</button>

jsx的写法:

<button>
    {this.$scopedSlots.default()}
</button>

具名插槽模板写法:

<button>
    <slot name="before"></slot>
    <slot ></slot>
</button>

jsx写法:

let before = '';
if (this.$scopedSlots.before) {
    before = this.$scopedSlots.before(props => props.text);
}
return (<button>
    { before }
    {this.$scopedSlots.default()}
</button>)

作用域插槽模板写法:

<slot :isAdvancedPanelShow="isAdvancedPanelShow"></slot>

jsx写法:

{this.$scopedSlots.default({
    isAdvancedPanelShow: this.isAdvancedPanelShow
})}

动态组件名字

还记得官网怎么介绍 createElement 获取js的完全编程能力吗? 举了一个根据不同的等级使用不同标题的案例:

Vue.component('anchored-heading', {
  render: function (createElement) {
    return createElement(
      'h' + this.level, // 标签名称
      this.$slots.default // 子节点数组
    )
  },
  props: {
    level: {
      type: Number,
      required: true
    }
  }
})

这个案例通过jsx的写法为:

Vue.component('anchored-heading', {
  render: function (h) {
   const TagName = 'h' + this.level;
    return <TagName>{ this.$slots.default(this.props) }</TagName>
  },
  props: {
    level: {
      type: Number,
      required: true
    }
  }
})

要知道,vuecreateElement函数的第一个参数可以是一个 HTML 标签名、组件选项对象,或者resolve了上述任何一种的一个async函数。

动态组件编排

在实际开发中, 碰到一种场景, 有组件CompA, CompB, CompC 。如果是a情况,需要在当前组件按照CompA, CompB, CompC顺序展示, 如果是不是a情况, 则通过CompC, CompB, CompA来展示。jsx写法为:

render(h) {
 // 假设组件A是需要特殊设置一些属性的
 const compA = (<CompA name="joyer">hellow word</CompA>)
 const content = this.status === 'a' ? [compA, CompB, CompC] : [CompC, CompB, compA];
 return (<div>{content}</div>)
}

这里末尾也可以这样写:

return (<div>{...content}</div>)

但在有些编辑器会报错,因为在react不允许这样写:

Spread children are not supported in React.

在babel官方编辑器中尝试

可以在babel官方提供的编辑器jsx尝试代码,不过需要记得在左边最下角添加babel=plugin-transform-vue-jsx插件:

添加vue-jsx插件

查看原文

赞 12 收藏 5 评论 1

trionfo1993 提出了问题 · 2019-08-28

typescript 可选参数是泛型如何给其默认参数?

export interface PageModelParams {
  pageIndex: number
  pageSize: number
}

export default function usePageModel<T extends Object, P extends PageModelParams = PageModelParams>(
  path: string,
  _params: P,
) {
  const [data, setData] = useState<T[]>([])
  const [params, setParams] = useState<P>(_params)

  /**
   * 拉数据
   */
  useEffect(
    function() {
      request
        .get<T[]>(path, {
          params,
        })
        .then(setData)
    },
    [params, path],
  )

  return {
    data,
    setParams,
  }
}

其中_params参数我想做成可选的,如果没有就用一个PageModelParams作为默认值
但是改为可选参数之后会显示'P' could be instantiated with a different subtype of constraint 'PageModelParams'

关注 1 回答 0

trionfo1993 赞了文章 · 2019-05-14

[面试专题]跨域解决方案

跨域产生

同源策略限制,同源是指:域名,协议,端口相同。

1.跨域资源共享(CORS)

需要被请求方的服务端设置: Access-Control-Allow-Origin。兼容性不够好,在IE10以下的浏览器不支持。

2.服务器代理

A客户端访问A服务器,并在A服务器上做代理访问B服务器把请求结果返回A客户端,即实现了A客户端请求B服务器的跨域需求。

3.JSONP

原理:所有具有src属性的HTML标签都是可以跨域的,包括<script><img><iframe>,所以我们通常会把一些图片资源放到第三方服务器上,然后可以通过<img>标签的src属性引用。

  1. 首先在客户端注册一个callback, 然后把callback的名字传给服务器。

  2. 服务器先生成 json 数据。将 json 数据直接以入参的方式,放置到 callback中,这样就生成了一段 js 语法的文档,返回给客户端。

  3. 客户端浏览器,解析script标签,并执行返回的 javascript 代码,此时数据作为参数,传入到了客户端预先定义好的 callback 函数里.(动态执行回调函数)

查看原文

赞 4 收藏 17 评论 0

trionfo1993 回答了问题 · 2019-05-14

用pdf.js预览pdf文件,找不到字体,字都变成了方框

如果是使用webpack的话 先import进来 获取url

关注 3 回答 2

trionfo1993 赞了文章 · 2018-09-06

浅谈前端发展的必然性

前言

这是我第一次写文章

很早就有想写技术博客的想法,但一直都没开始做这件事。
其实在开发的过程中,把自己遇到的一些问题记录下来,自己悟到的一些心得记录下来,对自己的知识展示与巩固都有很好的帮助。
因此,从这次起,我将会以每周至少一篇技术相关文章来要求自己,希望早日能成为自己心目中的技术大神。


浅谈前端发展的必然性
前端这两年发展很快,而我入行做程序员的时间也只有两年多一些,所以只能是浅谈。
不喜勿喷,多多担待。也想和更多的同行有交流


ajax技术-前后端分离

其实以我看来前端的发展有很大的必然性,有一些“道”可循。其主要变革我觉得都是因为ajax的普及。众所周知,在ajax没有出现之前,表单提交是需要重新请求页面的(原生的from表单submit事件),所以ajax技术的出现解决了这个问题以得到更好的用户体验。这个发展可以说是必然的,毕竟对于程序员来说有需求就要实现嘛。在ajax全面普及之时我们发现ajax可以做的更多,可以由页面发起单独请求所需数据,让页面更加的灵活,让页面动了起来~而不是死死的写啥展示啥,有了这个方向的发展,其实前后端就有了分离的可能。

越来越多的数据处理需求

在互联网用户越来越多以后,每一条请求每一条数据都需要服务端来计算,渲染等,服务器需要减负,而减负的方法就是让每个客户端来处理一些公开的数据处理。这样就可以最好的做到均衡,我客户端只处理一些我自己的事情,也不累,可很快,而服务端就可以大大的提高硬件效率。

模块化

在页面端处理越来越多的逻辑后,前端的请求越来越多,页面中的逻辑计算也越来越多。在前端处理越来越多的请求,处理越来越多的数据以后,往往单张页面也会变得很复杂,很累赘。所以前端工程化模块化也就应运而生了。像现在的主流框架vue、angular、react都是此类优秀的解决方案。

SSR(服务端渲染)

而模块化工程化后,带来了两个问题
1.搜索引擎seo问题。因为很多模块化工程化都十分依赖js,很多都是按需加载,页面中没有许多搜索引擎需要的关键字,这样一来很多对外的,to C端客户的页面被点开的频率就会降低。
2.过多的网络请求下,数据量过多的情况下我的页面被打开的速度大大降低了,由于网络速度的限制以及多条请求的耗时(要知道完成一次前后端互交浏览器与服务器之间是有多次交流的,可参阅网络请求协议)

为了解决这两个问题,所以就有了SSR。react有next.js vue有nuxt.js 还有许多原生的/node端的SSR解决方案。

结语

以上就是我目前想道的前端发展中产生的一些想法。比较笼统,比较大方向。

当然,这是一条线下来的,中间还有许多发展分支没有提到,如:
1.前后端分离的node中间岛概念
2.APP相关的hybird混合开发
3.Dcloud、reactNative、ionic之类的直接打包app
4.解决js单线程原因造成页面卡顿而产生的promise异步方法
5.electron、nw.js之类的桌面应用打包方法
6.手机应用便捷的小程序
...
等等
前端要学习有很多,就以上提到发展来说大家都可以看到,技术是不断完善的。总是会有问题会出现,也总会有解决办法。程序员不就是一个不断挖坑和填坑的职业么,所以不要在任何时候对技术放弃信心,他总会有解决的办法方案,学习再学习

查看原文

赞 3 收藏 2 评论 0

trionfo1993 回答了问题 · 2018-07-17

vue axios在IE上无法请求 报这个错误

...IE不支持Promise,你需要加babel-polyfill获取promise-polyfill

关注 2 回答 1

trionfo1993 回答了问题 · 2018-07-14

解决今天遇到跨域问题了,想请问服务器端不准跨域,客户端无论如何都请求不到数据??

用webworker可以绕过 简单来说就是开一个webworker来请求数据 得到之后回传回来

关注 4 回答 3

trionfo1993 回答了问题 · 2018-07-13

同源策略限制跨域请求,依然可以执行和访问程序

跨域是浏览器的问题,浏览器不信任返回回来的包拒绝了返回给程序,但是实际上 后台不受影响的,后台该怎么接受就怎么接受,该怎么处理就怎么处理

关注 3 回答 2

trionfo1993 回答了问题 · 2018-07-12

解决一个端口只能由一个程序使用,那为什么tcp中多个client可以连接上一个server的同一个端口?

计算机原理,linux多用户其实还是单用户,但是切换的够快就感觉是在并发使用了

关注 6 回答 4

trionfo1993 回答了问题 · 2018-04-01

解决vue项目在安卓上打开页面只能显示app.vue的背景颜色,样式什么的都不能显示

加个babel-polyfill试试

关注 6 回答 3

认证与成就

  • 获得 13 次点赞
  • 获得 16 枚徽章 获得 0 枚金徽章, 获得 3 枚银徽章, 获得 13 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

注册于 2017-03-03
个人主页被 780 人浏览