金沙8331网址精晓Vue中的Render渲染函数,在vue中使用jsx语法的运用格局_vue

什么是JSX?

接头Vue中的Render渲染函数

JSX便是Javascript和XML结合的一种格式。React发明了JSX,利用HTML语法来创建虚构DOM。当境遇

VUE平时接收template来创造HTML,然后在某些时候,我们必要利用javascript来创设html,当时大家必要采取render函数。
比方说如下笔者想要实现如下html:

自己干什么要在vue中用JSX?

<div id="container">
  <h1>
    <a href="#">
      Hello world!
    </a>
  </h1>
</div>

想折腾一下嘛,开玩笑.最伊始是因为近些日子在就学react,在里边心得了一把jsx语法,开掘也并未有人家说的十分的痛苦的感觉啊,于是就想尝试在vue中也试下,废话十分的少说,先来用代码来看下两个的区分吧.

咱俩会如下使用:

ps:vue中多数风貌是不必要用render函数的,依旧用模板更洗练直观.

<!DOCTYPE html>
<html>
  <head>
    <title>演示Vue</title>
    <style>

    </style>
  </head>
  <body>
    <div id="container">
      <tb-heading :level="1">
        <a href="#">Hello world!</a>
      </tb-heading>
    </div>
  </body>
  <script src="./vue.js"></script>

  <script type="text/x-template" id="templateId">
    <h1 v-if="level === 1">
      <slot></slot>
    </h1>
    <h2 v-else-if="level === 2">
      <slot></slot>
    </h2>
  </script>

  <script>
    Vue.component('tb-heading', {
      template: '#templateId',
      props: {
        level: {
          type: Number,
          required: true
        }
      }
    });
    new Vue({
      el: '#container'
    });
  </script>
</html>

使用template

查看效果

// item.vue               export default { name: "item", props:{ id:{ type:Number, default:1 } } }

如上代码是依赖参数
:level来浮现区别等级的标题中插入锚点成分,大家需求再一次的接受<slot></slot>.

item组件中便是抽取父组件传过来的id值来呈现差异的h标签,v-if能够说用到了”十二万分”,何况写了重重个冗余的slot

下边大家来尝试接纳 render函数重写下面的demo;如下代码:

使用render函数和jsx

<!DOCTYPE html>
<html>
  <head>
    <title>演示Vue</title>
    <style>

    </style>
  </head>
  <body>
    <div id="container">
      <tb-heading :level="2">
        <a href="#">Hello world!</a>
      </tb-heading>
    </div>
  </body>
  <script src="./vue.js"></script>

  <script>
    Vue.component('tb-heading', {
      render: function(createElement) {
        return createElement(
          'h' + this.level,    // tag name 标签名称
          this.$slots.default  // 组件的子元素
        )
      },
      props: {
        level: {
          type: Number,
          required: true
        }
      }
    });
    new Vue({
      el: '#container'
    });
  </script>
</html>
// item.vue export default { name: "item", props:{ id:{ type:Number, default:1 } }, render(){ const hText=` &lt;h${this.id}&gt;${this.$slots.default[0].text}&lt;/h${this.id}&gt; ` return &lt;div domPropsInnerHTML={hText}&gt;&lt;/div&gt; } }

金沙8331网址精晓Vue中的Render渲染函数,在vue中使用jsx语法的运用格局_vue。查阅效果

再增进父组件来决定props的值。父组件不做相比还用古板的template格式,

如上
render函数代码看起来特简单就贯彻了,组件中的子成分存储在组件实列中
$slots.default 中。

// list.vue  Hello World 下一个  import Title from './item' export default { name: "list", data() { return { id:1 } }, components: { "h-title":Title }, methods:{ next(){ ++this.id } } }

理解createElement
Vue通过确立一个设想DOM对实在的DOM产生变化保存追踪,如下代码:
return createElement(‘h1’, this.title);
createElement重临的是富含的音讯会报告VUE页面上急需渲染什么样的节点及其子节点。大家称那样的节点为伪造DOM,能够简写为VNode,

运维后页面就渲染出了h1 or h2 or
h3标签,同期slot也唯有二个,点击切换props的值,也会显得差异的h标签。第三种写法就算不是很直接,不过省去了大多冗余代码,页面一下舒服了好些个。

createElement 参数

// @return {VNode}
createElement(
  // {String | Object | Function}
  // 一个HTML标签字符串,组件选项对象,或者一个返回值类型为String/Object的函数。该参数是必须的
  'div',

  // {Object}
  // 一个包含模板相关属性的数据对象,这样我们可以在template中使用这些属性,该参数是可选的。
  {

  },

  // {String | Array}
  // 子节点(VNodes)由 createElement() 构建而成。可选参数
  // 或简单的使用字符串来生成的 "文本节点"。
  [
    'xxxx',
    createElement('h1', '一则头条'),
    createElement(MyComponent, {
      props: {
        someProp: 'xxx'
      }
    })
  ]
)

没了v-if,v-for,v-model怎么办?

略知皮毛深远data对象。
在模板语法中,我们得以选用 v-bind:class 和 v-bind:style
来绑定属性,在VNode数据对象中,上面包车型客车属性名的字段品级是最高的。
该对象允许大家绑定普通的html本性,就如DOM属性相同。如下:

不用焦急,这一个指令只是黑法力,用js十分轻松达成。

{
  // 和`v-bind:class`一样的 API
  'class': {
    foo: true,
    bar: false
  },
  // 和`v-bind:style`一样的 API
  style: {
    color: 'red',
    fontSize: '14px'
  },
  // 正常的 HTML 特性
  attrs: {
    id: 'foo'
  },
  // 组件 props
  props: {
    myProp: 'bar'
  },
  // DOM 属性
  domProps: {
    innerHTML: 'baz'
  },
  // 事件监听器基于 `on`
  // 所以不再支持如 `v-on:keyup.enter` 修饰器
  // 需要手动匹配 keyCode。
  on: {
    click: this.clickHandler
  },
  // 仅对于组件,用于监听原生事件,而不是组件内部使用 `vm.$emit` 触发的事件。
  nativeOn: {
    click: this.nativeClickHandler
  },
  // 自定义指令。注意事项:不能对绑定的旧值设值
  // Vue 会为您持续追踪
  directives: [
    {
      name: 'my-custom-directive',
      value: '2',
      expression: '1 + 1',
      arg: 'foo',
      modifiers: {
        bar: true
      }
    }
  ],
  // Scoped slots in the form of
  // { name: props => VNode | Array<VNode> }
  scopedSlots: {
    default: props => createElement('span', props.text)
  },
  // 如果组件是其他组件的子组件,需为插槽指定名称
  slot: 'name-of-slot',
  // 其他特殊顶层属性
  key: 'myKey',
  ref: 'myRef'
}

v-if

地方的data数据或然不太好精通,大家来看八个demo,就精通它是怎么样使用的了,如下代码:

 render(){ return (  {this.show?'你帅':'你丑'}  ) }
<!DOCTYPE html>
<html>
  <head>
    <title>演示Vue</title>
    <style>

    </style>
  </head>
  <body>
    <div id="container">
      <tb-heading :level="2">
        Hello world!
      </tb-heading>
    </div>
  </body>
  <script src="./vue.js"></script>

  <script>
    var getChildrenTextContent = function(children) {
      return children.map(function(node) {
        return node.children ? getChildrenTextContent(node.children) : node.text
      }).join('')
    };
    Vue.component('tb-heading', {
      render: function(createElement) {
        var headingId = getChildrenTextContent(this.$slots.default)
          .toLowerCase()
          .replace(/W+/g, '-')
          .replace(/(^-|-$)/g, '')
        return createElement(
          'h' + this.level,
          [
            createElement('a', {
              attrs: {
                name: headingId,
                href: '#' + headingId
              },
              style: {
                color: 'red',
                fontSize: '20px'
              },
              'class': {
                foo: true,
                bar: false
              },
              // DOM属性
              domProps: {
                innerHTML: 'baz'
              },
              // 组件props
              props: {
                myProp: 'bar'
              },
              // 事件监听基于 'on'
              // 所以不再支持如 'v-on:keyup.enter' 修饰语
              // 需要手动匹配 KeyCode  
              on: {
                click: function(event) {
                  event.preventDefault();
                  console.log(111);
                }
              }
            }, this.$slots.default)
          ]
        )
      },
      props: {
        level: {
          type: Number,
          required: true
        }
      }
    });
    new Vue({
      el: '#container'
    });
  </script>
</html>

写三元表明式只可以写简单的,那么复杂的还得用if/else

相应的属性使用方式和地方相符不仅能够了,大家得以展开页面查看下效果也是可以的。如下

 render(){ let ifText if{ ifText= }else{ ifText= } return (  {ifText}  ) }

翻看效果

v-for

VNodes 不必然必需独一 (文书档案中说要独一)
文书档案中说 VNode必需独一;说 下边包车型大巴 render function 是行不通的:
然则本身经过测量试验时方可的,如下代码:

 data(){ return{ show:false, list:[1,2,3,4] } }, render(){ return (  {this.list.map=>{ return  })}  ) }
<!DOCTYPE html>
<html>
  <head>
    <title>演示Vue</title>
    <style>

    </style>
  </head>
  <body>
    <div id="container">
      <tb-heading :level="2">
        Hello world!
      </tb-heading>
    </div>
  </body>
  <script src="./vue.js"></script>

  <script>
    Vue.component('tb-heading', {
      render: function(createElement) {
        var pElem = createElement('p', 'hello world');
        return createElement('div', [
          pElem, pElem
        ])
      },
      props: {
        level: {
          type: Number,
          required: true
        }
      }
    });
    new Vue({
      el: '#container'
    });
  </script>
</html>

在jsx中{}中间是不能够写if/for语句的只可以写表明式,所以就用map来当循环,用莫斯利安表明式来当推断了

查看效果

v-model

选用Javascript替代模板成效
 v-if 和 v-for
template 中有 v-if 和 v-for, 不过vue中的render函数没有提供专项使用的API。
譬喻如下:

近年来在帮公司面试令人开采v-model很四个人都不明白语法糖是什么?然后有一些人讲自个儿得以用原生js完毕,可是她们以致不晓得在vue中怎么落到实处,行吗,多少个点:传值和监听事件改换值。

<ul v-if="items.length">
  <li v-for="item in items">{{ item.name }}</li>
</ul>
<p v-else>No item found.</p>
  export default { name: "item", data(){ return{ show:false, list:[1,2,3,4], text:'', } }, methods:{ input{ this.text=e.target.value } }, render(){ return ( &lt;div&gt; &lt;input type="text" value={this.text} onInput={this.input}/&gt; &lt;p&gt;{this.text}&lt;/p&gt; &lt;/div&gt; ) } }

在render函数中会被javascript的 if/else 和map重新完结。如下代码:

怎么用自定义组件?

<!DOCTYPE html>
<html>
  <head>
    <title>演示Vue</title>
    <style>

    </style>
  </head>
  <body>
    <div id="container">
      <tb-heading>
        Hello world!
      </tb-heading>
    </div>
  </body>
  <script src="./vue.js"></script>

  <script>
    Vue.component('tb-heading', {
      render: function(createElement) {
        console.log(this)
        if (this.items.length) {
          return createElement('ul', this.items.map(function(item){
            return createElement('li', item.name);
          }))
        } else {
          return createElement('p', 'No items found.');
        }
      },

      props: {
        items: {
          type: Array,
          default: function() {
            return [
              {
                name: 'kongzhi1'
              },
              {
                name: 'kongzhi2'
              }
            ]
          }
        }
      }
    });
    new Vue({
      el: '#container'
    });
  </script>
</html>

很简单,只须求导入进来,不用再在components属性证明了,直接写在jsx中诸如

翻看效果

 import HelloWolrd from './HelloWorld' export default { name: "item", render(){ return  } }

v-model

事件,class,style,ref等等怎么绑定?

render函数中一向不 与
v-model相应的api,大家必须团结来落到实处相应的逻辑。如下代码能够兑现:

render  { return (   )}
<!DOCTYPE html>
<html>
  <head>
    <title>演示Vue</title>
    <style>

    </style>
  </head>
  <body>
    <div id="container">
      <tb-heading @input="inputFunc">
        Hello world!
      </tb-heading>
    </div>
  </body>
  <script src="./vue.js"></script>

  <script>
    Vue.component('tb-heading', {
      render: function(createElement) {
        var self = this;
        return createElement('input', {
          domProps: {
            value: '11'
          },
          on: {
            input: function(event) {
              self.value = event.target.value;
              self.$emit('input', self.value);
            }
          }
        })
      },
      props: {

      }
    });
    new Vue({
      el: '#container',
      methods: {
        inputFunc: function(value) {
          console.log(value)
        }
      }
    });
  </script>
</html>

上面有个地点须求静心,当给自定义组件绑定事件时用nativeOnClick,而模板格式是用@click.native,其余当用到给函数式组件绑定事件时就有一点小坑了下边说。

查看效果

JSX中的函数式组件

理解插槽

函数式组件无状态,无this实例,上面是vue文书档案中提到的一段话:

可以从 this.$slots 获取VNodes列表中的静态内容:如下代码:

因为函数式组件只是二个函数,所以渲染开支也低比比较多。不过,对长久化实例的缺点和失误也意味着函数式组件不汇合世在
Vue devtools 的零零件树里。

<!DOCTYPE html>
<html>
  <head>
    <title>演示Vue</title>
    <style>

    </style>
  </head>
  <body>
    <div id="container">
      <tb-heading :level="2">
        <a href="#">Hello world!</a>
      </tb-heading>
    </div>
  </body>
  <script src="./vue.js"></script>

  <script>
    Vue.component('tb-heading', {
      render: function(createElement) {
        return createElement(
          'h' + this.level,    // tag name 标签名称
          this.$slots.default  // 子组件
        )
      },
      props: {
        level: {
          type: Number,
          required: true
        }
      }
    });
    new Vue({
      el: '#container'
    });
  </script>
</html>

自个儿个人通晓因为没了状态,少了重重响应式的拍卖,还恐怕有生命周期等经过会增速和减少内部存款和储蓄器占用呢?函数式组件也能够在模板格式中用只须要这么

翻看效果

这jsx中的函数式组件呢?也超轻易只需追加安插functional: true就足以了

领悟函数式组件

这函数式组件未有了this 实例怎么绑定事件怎么获取props呢?

函数式组件大家标识组件为 functional, 意味着它无状态(未有data卡塔尔(قطر‎,
无实列(未有this上下文卡塔尔(قطر‎。
贰个函数式组件像下边那样的:

构件须求的一切都是通过上下文字传递递,包涵:

Vue.component('my-component', {
  functional: true,
  // 为了弥补缺少的实列
  // 提供第二个参数作为上下文
  render: function(createElement, context) {

  },
  // Props 可选
  props: {

  }
})

props : 提供具有 prop 的对象 children: VNode 子节点的数组 slots:
重临全体插槽的指标的函数
data:传递给组件的数量对象,并将以此组件作为第一个参数字传送入 createElement

组件须要的整整经过上下文字传递递,满含如下:
props: 提供props对象
children: VNode子节点的数组
slots: slots对象
data: 传递给组件的data对象
parent: 对父组件的援用
listeners: (2.3.0+) 二个暗含了组件上所注册的 v-on
侦听器的靶子。那只是一个指向性 data.on 的外号。
injections: (2.3.0+) 如若选择了 inject
选项,则该对象蕴含了应当被注入的习性。

地点作者只列举了有个别属性,那么些是非函数式组件的东西,对于函数式组件vue
扩大了context对象,须求用作render
第四个参数传入,this.$slots.default更新为context.children
props原来是平昔挂在this上的,现在成为context.props挂在了context.props上。this.data变为了context.data

在累计 functional: true 之后,组件的 render 函数之间轻松更新增加 context
参数,this.$slots.default 更新为 context.children,之后this.level 更新为
context.props.level。
平常来讲代码演示:

亟待专心的是对此函数式组件,未有被定义为prop的特点不会自动增加到组件的根元素上,意思正是供给大家手动增多到组件根成分了,看个例子吗

<!DOCTYPE html>
<html>
  <head>
    <title>演示Vue</title>
    <style>

    </style>
  </head>
  <body>

    <div id="container">
      {{msg}}
      <choice>
        <item value="1">test</item>
      </choice>
    </div>

  </body>
  <script src="./vue.js"></script>

  <script>
    Vue.component('choice', {
      template: '<div><ul><slot></slot></ul></div>'
    });

    Vue.component('item', {
      functional: true,
      render: function(h, context) {
        return h('li', {
          on: {
            click: function() {
              console.log(context);
              console.log(context.parent);
              console.log(context.props)
            }
          }
        }, context.children)
      },
      props: ['value']
    })

    new Vue({
      el: '#container',
      data: {
        msg: 'hello'
      }
    });
  </script>
</html>
//父组件 ...省略无关代码 render(){ return (  ) }//Item.vue组件export default { functional:true, name: "item", render{ return (  {context.props.data}  ) } }

查看效果

地点代码期望的是.large类名传入到了Item的根成分上,可是其实远非。大家要求扩充点东西

// Item.vueexport default { functional:true, name: "item", render{ return (  {context.props.data}  ) } }

专一到,通过开展运算符把全体的质量增添到了根成分上,那些context.data就是你在父组件给子组件扩展的习性,他会跟你在子成分根成分的个性智能归并,今后.large类名就传进来了。这几个很有用,当您在父组件给子组件绑定事件时就须要这么些了。上边说一个有关绑定事件的小坑

向 createElement 通过传播 context.data 作为第一个参数,大家就把
my-functional-button
上面装有的特征和事件监听器都传送下去了。事实上那是极其透明的,那个事件依然并不供给.native 修饰符

上面是vue官方网站的一段话,可是小编看了一次就忽视了一句很关键的话,正是最终一句,他说无需.native修饰符了?好先看代码

// 父组件 methods:{ show } }, render(){ return (  ) }

上边代码乍一看没毛病,自定义组件用onNativeClick嘛,结果正是不会弹窗。唉,最后读了几次刚才vue文书档案中的解释,才发觉原本函数式组件没有必要.native修饰符,对于template格式肯定一下就反应过来了,可是jsx的话,好啊,把地点的onNativeClick重新改为onClick就好了。

幸存项目什么成效能够用jsx代替呢?

本条实际上跟最开首自己例举的例证很像。小编在类型中用它来干掉了满屏的v-if/v-else

由于自家的政工是pad上的,供给是一套试卷有几十道标题,供给一屏只呈现一道难点,点击下一题展现下二个题,思路也比较轻松:

用二个num变量表示方今正在显示的标题索引 每一趟点击下一题按键时num++
用v-if来判定 num===1,num===2那样来决定展示哪个。

这一写,模板里面大多哟,由于大家的题目每道题的沙盘模拟经营可能都分裂等,所以不能够循环,只能手写全部。在此之前思虑过用动态组件来切换,不过甩掉了,因为尚未if直观啊。

下边看怎么用jsx优化一下

//父组件 export default { name: "list", data() { return { data:'我是函数式组件', id:1, tests:{ 1:第一道题, 2:第二道题, 3: } } }, methods:{ next(){ ++this.id } }, render(){ return (   下一题  ) } }

地点每道标题标布局都差异等

 //子组件,只接受数据展示,用函数式组件 export default { functional:true, name: "item", render{ return ( &lt;div {...context.data}&gt; {context.props.data} &lt;/div&gt; ) } }

上边未有用别样if/else剖断就完了了成效,这里用jsx笔者以为相比较稳当,不明白诸位大佬有怎么着其余思路?

最后

总计一下吗,大家平昔支出依然多用temlate因为直观简洁,各个指令用着很便利,等你感到用template写出的代码瞧着很冗余,或然想和睦说了算渲染逻辑比方循环,推断等等时方可思忖用JSX。其它推荐大家多用函数式组件提升质量。

第贰遍写小说,希望各位花时间看了的大佬以为哪个说的不太严苛还需多多原谅,提议意见小编都领受。

仿照效法资料

vue 渲染函数&jsx babel-plugin-transform-vue-jsx

上述正是本文的全体内容,希望对大家的读书抱有利于,也希望大家多都赐教脚本之家。

发表评论

电子邮件地址不会被公开。 必填项已用*标注