虚拟DOM技术(Virtual DOM,VDOM)

虚拟DOM技术(Virtual DOM,VDOM)

VDOM的第一个目的:完成在Vue下实现DOM操作的功能。
VDOM的第二个目的:实现比原生的DOM操作还要快的页面渲染机制。
VDOM的本质:利用js对象模拟DOM节点。
一、利用render函数代替组件中的template:
1、render函数的功能:在创建组件是实现DOM结构的生产,和template完全一致。
2、格式:

Vue.component(‘my-com’,{
   render:function(createElement){
     return createElement(‘div’);
}
//相当于 template:`<div></div>`
})

    使用组件:<my-com></my-com>

3、简化格式:

Vue.component(‘my-com’,{
   render:h=>h(‘div’)
})

4、创建一个带有文本内容的VDOM节点:

 <div>我天上课之前画了一个满之慧</div>
render:h=>h(‘div’,‘我天上课之前画了一个满之慧’)

5、创建一个VDOM节点:
带有名为box的类名,内联样式规定了宽度、高度、背景颜色,具备id属性和title属性。
能够为这个VDOM节点绑定鼠标经过和鼠标离开的事件。

<div class=“box” style=“width:5px;height:5px;background-color:red” id=“” title=“”
onmouseover=“” onmousemove=“”>
```
解决方案:使用h()函数的第二个参数,参数类型为{}。

格式:

h(‘tagName’,{
        class:{ //为VDOM节点设置类名 },
        style:{ //为VDOM节点设置内联样式},
        attrs:{ //为VDOM节点设置HTML属性},
        on:{ //为VDOM节点绑定事件},
        domProps:{ //为VDOM节点设置JavaScript中的节点属性}
})
例如:
render:h=>h('div',{
		class:{box:true},
		style:{width:'200px',height:'100px',backgroundColor:'#3385ff'},
		attrs:{id:'box',title:'鼠标经过显示文本'},
		on:{
			mouseover:()=>event.target.style.backgroundColor='#ff5857',
			mouseout:()=>event.target.style.backgroundColor='#3385ff'
		},
		domProps:{
			innerText:'我是通过h函数生成的VDOM节点',
			contentEditable:true
		}
	})

6、创建一个带有子节点的VDOM节点:
格式:

`h(‘div’,[h(),h()])`
例如:
 render:h=>h('div',{
		class:{box:true}
	},[
		h('h1','我是一级标题'),
		h('div',[
			h('p','我是一个段落'),
			h('a',{
				attrs:{href:'#'}
			},'百度百科')
		])
	])

二、根据现有组件创建VDOM节点:
1、例1:根据现有组件my-book创建VDOM节点。

Vue.component(‘my-book’,{
   template:`<div class=“book”>书名</div>`
})
Vue.component(‘my-com’,{
   render:h=>h(‘my-book’)
})

2、例2:根据带有插槽的现有组件创建VDOM节点。

  Vue.component('my-book',{
	   template:`<div class="book"><slot></slot></div>`
})
Vue.component('my-com',{
  // render:h=>h(‘my-book’,‘书名作者’)
render:h=>h('my-book',[h('div','我和我的VUE')])
})

3、例3:根据带有参数的现有组件创建VDOM节点。

 Vue.component('my-book',{
	template:`
		<div class="book">
			<p>书名:{{bookName}}</p>
			<p>作者:{{author}}</p>
			<p>出版社:{{publish}}</p>
		</div>
	`,
	props:['bookName','author','publish']
})

Vue.component('my-com',{
	render:h=>h('my-book',{
		props:{
			bookName:'满之慧与伏地魔',
			author:'裴嘉靖',
			publish:'金梅出版社'
		}
	})
})

4、例4:让现有组件作为VDOM节点的子节点。

 render:h=>h('div',[
		h('h1','2020年畅销书'),
		h('my-book',{
			props:{
				bookName:'满之慧与伏地魔',
				author:'裴嘉靖',
				publish:'金梅出版社'
			}
		})
	])

三、创建具备插槽的VDOM节点:
注意:具备插槽的VDOM节点不能使用箭头函数。
1、例1:创建具备一个匿名插槽的VDOM节点。
DOM结构格式:

template:`<div><slot></slot></div>`
render(h){
   return h(‘div’,this.$slots.default);
}

使用:

<my-com>我被放入匿名插槽中</my-com>
(1)创建一个下列格式的VDOM节点:
 <div><span style=“color:#ff5857;><slot></slot></span></div>
render(h){
		return h('div',[
			h('span',{
				style:{color:'#ff5857'}
			},this.$slots.default)
		])
}

(2)创建一个超级链接的VDOM节点。

  template:`<div><a :href=“url”><slot></slot></a></div>`
     render(h){
		return h('div',[
			h('a',{
				attrs:{href:this.url}
			},this.$slots.default)
		])
	  },
	  props:['url']
 使用:<my-com url=“https://www.baidu.com”>百度百科</my-com>

2、例2:创建具备多个具名插槽的VDOM节点。

template:`
  <div>
    <h1><slot name=“abc”></slot></h1>
    <h2><slot name=“xyz”></slot></h2>
</div>
`
    render(h){
		return h('div',[
			h('h1',this.$slots.abc),
			h('h2',this.$slots.xyz)
		])
	 }
使用:<my-com>
			<span slot="abc">哈利波特与魔法石</span>
			<span slot="xyz">JK罗琳</span>
	   </my-com>

3、例3:创建具备一个默认作用域插槽的VDOM节点。

render(h){
		return h('div',this.$scopedSlots.default({
			a:100,
			b:200,
			c:50
		}))
	 }
   <my-com>
		<template slot-scope="sc">
			{{sc.a}}+{{sc.b}}+{{sc.c}}={{sc.a+sc.b+sc.c}}
		</template>
    </my-com>

4、例4:创建具备多个具名的作用域插槽的VDOM节点。

render(h){
		return h('div',[
			h('h1',this.$scopedSlots.abc({a:100,b:200})),
			h('h2',this.$scopedSlots.xyz({x:'A',y:'B'}))
		])
	 }
    使用:<my-com>
				<template slot="abc" slot-scope="sc">
					{{sc.a}}+{{sc.b}}={{sc.a+sc.b}}
				</template>
				<template slot="xyz" slot-scope="sc">
					{{sc.x}}+{{sc.y}}
				</template>
    	   </my-com>

四、在render函数中使用Vue指令:
1、利用render函数实现的组件模板不能使用vue指令。
2、例:当list数组中的元素>3个时,遍历出数组的所有内容并显示出来,否则提示内容不
足。
(1)使用传统的template来创建组件。

 Vue.component('my-com',{
	template:`
		<div class="com">
			<div v-if="list.length>3">
				<ul>
					<li v-for="(item,index) in list">{{item}}</li>
				</ul>
			</div>
			<div v-else>
				<p>数据内容不足</p>
			</div>
		</div>
	`,
	props:['list']
})

(2)使用render函数来创建VDOM节点。

  Vue.component('my-com',{
	render(h){
		let vnode;
		if(this.list.length>3){
			//创建循环遍历的VDOM节点
			vnode=h('ul',this.list.map(item=>h('li',item)));
		}else{
			//创建提示数据不足的VDOM节点
			vnode=h('p','数据内容不足');
		}
		return h('div',{
			class:{com:true}
		},[vnode]);
	},
	props:['list']
})

五、在element-ui中使用render函数:
1、在element-ui的表格组件中,具备一个属性 render-header,该属性的功
能是返回列表头的内容。
(1)可以返回一个字符串作为表头的新标签内容。
(2)可以返回一个VDOM节点作为表头的内容。
2、如何在VDOM中为表单元素绑定数据(VDOM不能使用v-model指令):
在表单元素的input事件中,让表单元素的value属性的取值赋给一个侦听属性。
3、案例:

<template>
  <div class="hello">
    <el-table :data="tableData" style="width: 100%" :border="true">
      <el-table-column prop="date" label="日期" min-width="20%" align="center">
      </el-table-column>
      <el-table-column :render-header="renderHeader" prop="name" label="姓名" min-width="60%" align="center">
      </el-table-column>
      <el-table-column prop="address" label="地址" align="center">
      </el-table-column>
    </el-table>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      nameValue:'',
      tableData:[],      //表格显示的数据
      allData:[          //原始的所有数据
        {
          date:'2020-5-4',
          name:'张金梅',
          address:'河北省石家庄市'
        },
        {
          date:'2020-6-1',
          name:'裴嘉靖',
          address:'河北省邯郸市'
        },
        {
          date:'2020-7-1',
          name:'满之慧',
          address:'山东省'
        }
      ]
    }
  },
  mounted(){
    this.tableData=this.allData;
  },
  methods:{
    renderHeader(h){
      let that=this;
      return h('div',{
        on:{
          click:function(){
            //让子节点span消失,让子节点input显示
            let spanNode=document.querySelector('.span');
            let inputNode=document.querySelector('.input');
            spanNode.style.display='none';
            inputNode.style.display="inline-block";
            inputNode.focus();
          }
        }
      },[
        h('span',{
          class:{span:true}
        },'姓名'),
        h('input',{
          class:{input:true},
          style:{display:'none'},
          on:{
            blur(){
              let spanNode=document.querySelector('.span');
              let inputNode=document.querySelector('.input');
              spanNode.style.display="inline";
              inputNode.style.display="none";
            },
            input(){
              that.nameValue=event.target.value;
            }
          }
        })
      ])
    }
  },
  watch:{
    nameValue(newValue){
      this.tableData=this.allData.filter(item=>{
        return item.name.indexOf(newValue)!==-1;
      })
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>

</style>

认识一个开源的VDOM项目:Snabbdom
1、打包工具:parcel
安装 npm install -g parcel-bundler
执行项目:parcel index.html
打包:parcel build index.html
2、下载snabbdom
npm install snabbdom@0.7.4
snabbdom是使用TypeScript来进行书写的。
3、引入snabbdom:
 ES6:import from
 CommonJS:require()
例:import {h,init} from ‘snabbdom’
4、使用到的函数:
init():参数是数组,返回值为patch()函数。
patch():将生成的VDOM节点放入到挂载点的DOM结构内部。
h():生成VDOM节点。
例1:利用Snabbdom生成一个div节点,并放在HTML的结构中,实现Hell,Snabbdomo
功能。

import {h,init} from ‘snabbdom’;
let patch=init([]);
let vnode=h(‘div’,‘Hello,Snabbdom!);
let app=document.querySelector(‘#app’);
patch(app,vnode);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值