Vue.js 创建一个 CNODE 社区(6)

render

关于 render 的更详细的内容可以查看 Vue 官方文档

Vue 推荐在绝大多数情况下使用 template 来创建你的 HTML。然而在一些场景中,你真的需要 JavaScript 的完全编程的能力,这时你可以用 render 函数,它比 template 更接近编译器。

我们先设想一下这个场景:

使用 v-bind 和 slot ,实现组件切换的功能。通过监听父组件按钮的事件,改变父组件 level 的值,然后把新的值通过 props 传递给了子组件;然后进行 v-if 判断,显示对应的组件。

使用 template 做法

<div id="app">
      <my-child :level=‘level‘>
          我是组件中内容
      </my-child>
      <br>
      <button @click=‘changeFontSize(1)‘>改变字号-大</button>
      <button @click=‘changeFontSize(2)‘>改变字号-中</button>
      <button @click=‘changeFontSize(3)‘>改变字号-小</button>
      <template id=‘myTemp‘>
          <div>
            <h1 v-if=‘level==1‘><slot></slot></h1>
            <h2 v-if=‘level==2‘><slot></slot></h2>
            <h3 v-if=‘level==3‘><slot></slot></h3>
        </div>
      </template>
  </div>
Vue.component(‘myChild‘,{
    props:[‘level‘],
    template:‘#myTemp‘
})
var app = new Vue({
    el:‘#app‘,
    data:{
        level:3
    },
    methods:{
        changeFontSize:function(value){
            this.level = value
        }
    }
})

demo :JSbin

但是,如果有更多的组件需要进行判断和切换呢?

template 就会越写越长,并且我们可以看到:

每当点击按钮切换组件的时候,之前的组件移除后,他们的组件也会渲染在页面上,会堆积在 DOM 树中,导致代码变得冗余,难以维护。

通过 render

现在通过 render 函数来改写一下这个功能:

<div id="app">
      <my-child :level=‘level‘>
          我是组件中内容
      </my-child>
      <br>
      <button @click=‘changeFontSize(1)‘>改变字号-大</button>
      <button @click=‘changeFontSize(2)‘>改变字号-中</button>
      <button @click=‘changeFontSize(3)‘>改变字号-小</button>
  </div>
Vue.component(‘myChild‘,{
    props:[‘level‘],
    render:function(createElement){
        return createElement(‘h‘+this.level,this.$slots.default)
    }
})
var app = new Vue({
    el:‘#app‘,
    data:{
        level:3
    },
    methods:{
        changeFontSize:function(value){
            this.level = value
        }
    }
})

通过 render 处理可以让结构更简洁,代码也没有冗余:

demo : JSbin


render 详解

demo : JSbin

Vue.component(‘myChild‘,{
    props:[‘level‘],
    render:function(createElement){
        return createElement(‘h‘+this.level,this.$slots.default)
    }
})

在 render 函数的方法中,参数必须是 createElement。,createElement 的类型是 function,他会返回一个 vnode 虚拟节点。

  • createElement 的第一个参数

可以是 String | Object | Function

// String - HTML标签,会在组件所在的位置渲染一个 div 节点
render:function(createElement){
        return createElement(‘div‘)
    }
// Object - 一个含有数据选项的对象
render:function(createElement){
        return createElement({
            template:`<div></div>`
        })
    }
// Function - 一个方法,返回含有数据选项的对象
render:function(createElement){
        let createDom = function(){
            return {
                template:`<div></div>`
            }
        }
        return createElement(createDom)
    }
  • createElement 的第二个参数(可选)

createElement 的第二个参数是数据对象,只能是 object。

// Function - 一个方法,返回含有数据选项的对象
render:function(createElement){
    return createElement({
        template:`<div>这里字体是红色的</div>`
    },{
        class:{
            foo:true,
            bar:false
        },
        style:{
            color:‘red‘,
            fontSize:‘30px‘
        },
        attrs:{
            id:‘foo‘
        },
        // 用来显示原生的 dom 属性
        domProps:{
            innerHTML:`<span style=‘color:yellow;font-size:16px‘>这里是黄色的</span>`
        }
    })
}

可以看到,我们通过给 createElement 方法添加第二个参数,为第一个参数所创造的节点增添了不少的属性。

  • createElement 的第三个参数(可选)

第三个参数也是可选,String | Array,作为我们构建函数的子节点来使用的

render:function(createElement){
    return createElement(‘div‘,{
        class:{
            foo:true,
            bar:false
        }},[
        createElement(‘h1‘,‘创建子节点1‘),
        createElement(‘h6‘,‘创建子节点2‘)
    ])
}

可以看到,我们通过给 createElement 方法添加第三个参数,为第一个参数所创造的节点增添了两个子节点(h1/h6)以及分别为两个子节点添加了一个子节点(‘创建子节点1‘/‘创建子节点2‘)。


this.$slots在render函数中的应用

利用 createElement 的第三个参数可以存储数组、创建子节点的特点,可以把指定的 slot (this.$slots.slotName返回的是一个 vnode 数组)存储到某个节点中。

demo : JSbin

<div id="app">
    <child>
        <p>正文</p>
        <span>正文段落</span>
        <h1 slot=‘header‘>header</h1>
        <h2 slot=‘footer‘>footer</h2>
    </child>
</div>
Vue.component(‘child‘,{
    render:function(createElement){
        // 注意,这里的 header 是一个 vnode 数组,所以他是 createElement 的第三个参数
        let header = this.$slots.header
        let footer = this.$slots.footer
        let main = this.$slots.default
        return createElement(‘div‘,[
            createElement(‘header‘,header),
            createElement(‘main‘,main),
            createElement(‘footer‘,footer)
        ])
    }
})
var app = new Vue({
    el:‘#app‘
})

在 render 函数中使用 props 传递数据

和之前的例子一样:

<div id="app">
      <my-child :level=‘level‘>
          我是组件中内容
      </my-child>
      <br>
      <button @click=‘changeFontSize(1)‘>改变字号-大</button>
      <button @click=‘changeFontSize(2)‘>改变字号-中</button>
      <button @click=‘changeFontSize(3)‘>改变字号-小</button>
  </div>
Vue.component(‘myChild‘,{
    props:[‘level‘],
    render:function(createElement){
        return createElement(‘h‘+this.level,this.$slots.default)
    }
})
var app = new Vue({
    el:‘#app‘,
    data:{
        level:3
    },
    methods:{
        changeFontSize:function(value){
            this.level = value
        }
    }
})

v-model 在 render 函数中的应用

demo : JSbin

<div id="app">
    <app-component :name=‘name‘ v-model=‘name‘></app-component> <br>
    {{ name }}
</div>
Vue.component(‘app-component‘,{
    render:function(createElement){

        // 这里的 this 等于子组件的this
        let self = this
        return createElement(‘input‘,{
            domProps:{

                // 这句的作用是把父组件传递进来的值显示在输入框里
                value:self.name
            },
            on:{
                input:function(event){
                    self.$emit(‘input‘,event.target.value)
                }
            }
        })
    },
    props:[‘name‘]
})
var app = new Vue({
    el:‘#app‘,
    data:{
        name:‘lily‘
    }
})

首先我们注册了一个子组件,并且通过 render 函数渲染模板,其中设置了一个 value 属性和 input 的监听事件;

声明 self 是为了确定 this 的指向是子组件;

value 属性的值,是父组件通过 :name=‘name‘props 传递给子组件的;

子组件通过 v-model 绑定了父组件的数据 name,当用户在输入框中输入时,我们在子组件中设置的监听事件就会触发 $emit 事件,把输入框中的 value 传递给了 v-model,v-model 更新了 name 的值为 value,从而实现子组件传值给父组件。


作用域插槽在render函数中的使用

demo : JSbin

<div id="app">
    <app-component>
    <template scope=‘prop‘>
        {{ prop.text}} <br>
        {{ prop.msg}}
    </template>
    </app-component>
</div>
Vue.component(‘app-component‘,{
    render:function(createElement){

        // 其实这句话就相当于之前的 template:`<div><slot text=‘scopeText‘ msg=‘scopeMsg‘></slot></div>`
        return createElement(‘div‘,this.$scopedSlots.default({
            text:‘scopeText‘,
            msg:‘scopeMsg‘
        }))
    }
})
var app = new Vue({
    el:‘#app‘
})

函数化组件的应用

之前创建的锚点标题组件是比较简单,没有管理或者监听任何传递给他的状态,也没有生命周期方法。它只是一个接收参数的函数。在这个例子中,我们标记组件为 functional,这意味它是无状态 (没有响应式数据),无实例 (没有 this 上下文)。

组件需要的一切都是通过上下文(传入的 context)传递

在添加 functional: true 之后,锚点标题组件的 render 函数之间简单更新增加 context 参数,this.$slots.default 更新为 context.children,之后this.level 更新为 context.props.level。

demo : JSbin

<div id="app">
    <app-component></app-component>
</div>
Vue.component(‘app-component‘,{
    functional: true,
    render:function(createElement,context){
        return createElement(‘button‘,{
            on:{
                click:function(){
                    console.log(context)
                    console.log(context.parent)
                }
            }
        },‘点击我查看上下文‘)
    }
})
var app = new Vue({
    el:‘#app‘,
})

关于 render,学习就先到这儿了。

得赶紧了解完基础概念,才能更快地学到实战部分...

原文地址:https://www.cnblogs.com/No-harm/p/9749157.html

时间: 2024-08-02 20:12:19

Vue.js 创建一个 CNODE 社区(6)的相关文章

Vue.js 创建一个 CNODE 社区(2)

还是继续入门 demo 这篇博文应该有点长,因为觉得了解了 computed 之后,应该还会继续学下去,所以这里会包含 computed 和 v-bind 的相关学习内容. computed 什么是计算属性 所有的计算属性都以函数的形式写在 Vue 实例内的computed 选项内,最终返回计算后的结果. 为什么使用计算属性以及如何使用 逻辑过长,会变的臃肿,难以维护. 使用计算属性可以完成各种复杂的逻辑,包括运算.函数调用等,只要最终返回一个结果即可. 如计算一个购物车总价: 计算属性还可以依

Vue.js 创建一个 CNODE 社区(3)

Vue 中的内置指令 demo 通过 demo 了解 Vue 中一些常用的内置指令. 涉及到 v-cloack / v-once / 条件循环指令(v-if / v-else-if / v-else) / v-show / 列表遍历渲染 (v-for) / 数组更新.过滤排序 / 方法和事件 (修饰符) 等... 以下是全部的 demo: JSbin v-cloak 作用:解决初始化慢导致页面闪动的最佳实践(初始化慢时会显示未渲染好的页面,而 v-cloak 则让没有渲染好的部分隐藏起来,渲染好

如何用Express.js &amp; Vue.js 创建一个用比特币支付的在线商店!

#  如何用Express.js & Vue.js 创建一个用比特币支付的在线商店! 如果你想创建一个在线商店,并用比特币等加密货币来支付,那么这里提供了一个很好的解决方案.Express.js是一个轻量级 MVC架构的Web开发框架,适用于Web服务器端开发.Vue.js是一个渐进式的前端开发框架,你可以自由选择需要的模块集成了你的项目中.Mixin Payment是一个开源的,基于Mixin Network开发的加密货币支付方案. ## 准备工作: 先安装以下依赖包!- Go lang  1

Vue.js 创建多人共享博客

多人共享博客 上一个项目:仿 CNODE 社区 刚完成,感觉有点意犹未尽,对于 登录 这一块老师并没有展开,我先是用了 localStorage 自己瞎搞,跑通之后想了下,vuex 不是专门做全局状态管理的么?那么用 vuex 做登录是最合适不过的呀.于是又搜了些别人用 vuex 做登录状态管理的案例,算是搞明白了. 现在选择了若愚老师的这个项目,主要是巩固一下对 vue 的认识,同时对 vuex 做个更详细的了解. 本项目做一款多人共享博客,包含首页.用户文章列表.登录.注册.个人管理.编辑.

基于vue的nuxt框架cnode社区服务端渲染

nuxt-cnode 基于vue的nuxt框架仿的cnode社区服务端渲染,主要是为了seo优化以及首屏加载速度 线上地址 http://nuxt-cnode.foreversnsd.cngithub地址 https://github.com/Kim09AI/nu... 技术栈 vue vue-router vuex nuxt axios simplemde ES6/7 stylus 目录结构 ├─npm-shrinkwrap.json ├─nuxt.config.js # nuxt配置文件 ├

使用vue.js仿一个链家

Vue全家桶+localstorage+socket.io简单仿一个链家 在线预览地址首先上项目和预览地址 https://luxroid.com/lianjia/#/Github地址 https://github.com/mixihome/lianjia 注意 如果要在本地运行安装完依赖之后如果报错请手动使用淘宝镜像安装node-sass和sass-loader 确保可以运行建议使用F12移动端模式预览???? 使用到的技能点Vue.js : 前端页面展示Vuex : 全局状态通信axios

vue.js 创建组件 子父通信 父子通信 非父子通信

1.创建组件 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>创建组件</title> <script src="https://unpkg.com/vue/dist/vue.js"></script> </head> <body> &l

关于vue如何创建一个自定义组件(这是项目中经常得用的)

1. 首先作大米饭我们得有米吧 要不 巧妇难为无米之炊啊  因此先买好我们自己的大米也就是创建组件文件,这里我假设要创建一个自己loading效果组件 那么我们就先创建 loading.vue 里面的代码根据vue template相关规则写就可以 这里就不在赘述了 我只写一个最最简单的例子 2.ok了 米就这么愉快的买好了 那么有了米我们现在只需要把他放在锅里!那么这个锅是谁呢!好吧我们自己来背这个锅,我们创建一个相关的.js文件 通常组件都是一个功能自己一个文件夹那么每个组件都应该有自己独立

【vue】创建一个vue前端项目,编译,发布

[一]mac检查是否安装node.js nvm --version =>0.33.9 node -v =>v10.7.0 [二]安装vue-cli cnpm install --global vue-cli [三]创建一个vue项目.基于 # 创建一个基于 webpack 模板的新项目 $ vue init webpack my-project # 这里需要进行一些配置,默认回车即可 原文地址:https://www.cnblogs.com/shangxiaofei/p/9429512.htm