某视频剪辑软件的使用相信大家都很熟练了,使用起来简单。但是大部分人不知道其内部的原理是怎么样的,今天我们就来一起实现一个简单的某视频剪辑软件
Object.defineProperty()
实现之前我们得先看一下Object.defineProperty的实现,因为某视频剪辑软件主要是通过数据劫持来实现的,通过获取、设置来完成数据的读取和更新。
var obj={ name : 'wc肢' } var age=24对象。define property(obj,' age ',{ enumerable: true,//可枚举可配置:假,//不能再定义get () { return age },set (newVal) { console.log('我改变了,年龄-(NewVal);age=NewVal } })obj。24岁。年龄=25岁;我改变了24 - 25 25从上面可以看到通过得到获取数据,通过设置监听到数据变化执行相应操作,还是不明白的话可以去看看Object.defineProperty文档。
流程图
超文本标记语言代码结构
div id='wrap' p v-html='test'/p输入类型='text' v型='form '输入类型='text' v型='form '按钮@click='changeValue '改变值/button {{form}}/divjs调用
新Vue({ el: '#wrap ',data:{ form: '这是形式的值,测试: '强我是粗体/strong ',},方法: { change value(){ console。日志(这个。形成)这个。形式='值被我改变了,气不气?} } })Vue结构
类vue { constructor(){ } ProxyData(){ } observer(){ } compile(){ } CompileText(){ } }类watcher { constructor(){ } update(){ } } Vue构造函数构造函数主要是数据的初始化代用资料数据代理观察者劫持监听所有数据编制解析dom compileText解析数字正射影像图里处理纯双花括号的操作看守人更新视图操作某视频剪辑软件构造器初始化
class Vue {构造函数(options={ }){ this .$ El=文档。queryselector(选项。El);让数据=这个。数据=选项。数据;//代理数据,使其能直接this.xxx的方式访问数据,正常的话需要对象键(数据)。forEach((key)={ this。代理数据(密钥);});this.methods=options.methods //事件方法这个。watcher task={ };//需要监听的任务列表this.observer(数据);//初始化劫持监听所有数据编译这个$ El);//解析dom } }上面主要是初始化操作,针对传过来的数据进行处理
代用资料代理数据
类别Vue{构造函数(选项={ }){ 0.} proxyData(密钥){ 0让那个=这个;object . defineperproperty(即key,{ configurable: false,enumerable: true,get(){ return。数据[密钥];},设置(NewVal){即。data[key]=NewVal;} });} }上面主要是代理数据到最上层,这个。xxx的方式直接访问数据
观察者劫持监听
类别Vue{构造函数(选项={ }){ 0.} proxyData(密钥){ 0.}观察者(数据){让那个=这个Object.keys(数据)。forEach(key={ let value=data[key]this。watcher task[key]=[]对象。definepreproperty(data,key,{ configurable: false,enumerable: true,get(){ return value }),set(newValue){ if(newValue!==值){ value=新值。观察器任务[键].forEach(任务={ task。update()})} } })} }同样是使用Object.defineProperty来监听数据,初始化需要订阅的数据。
把需要订阅的数据到推到观察任务里,等到时候需要更新的时候就可以批量更新数据了。下面就是;遍历订阅池,批量更新视图。
set(newValue){ if(newValue!==value){ value=newValue //批量更新视图观察任务[键]。forEach(任务={ task。update()})} }编译解析数字正射影像图
类别Vue{构造函数(选项={ }){ 0.} proxyData(密钥){ 0.}观察者(数据){ 0.}编译(El){ var nodes=El。子节点;用于(设I=0;我节点。长度;I){ const node=nodes[I];if(节点。nodetype===3){ var text=node。文本内容。trim();if(!文本)继续;this.compileText(节点,' textContent ')} else if(节点。nodetype===1){ if(node。子节点。长度0){ this。编译(节点)} if(节点。hasattribute(' v-model ')(节点。标记名==' INPUT ' | |节点。标记名==' TEXARea '){ node。addeventlistener(' INPUT ',()={ let attrVal=node。getattribute(' v-model ')这个。观察任务.push(新的Watcher(节点,this,Attraval,' value ')节点。移除属性(' v-model ')return()={ this。data[Attraval]=节点。value } })()} if(节点。hasattribute(' v-html '){ let Attraval=node。getattribute(' v-html ');这个。watchertask[Atrval].push(新的Watcher(节点,this,Attroval,' innerHTML ')节点。移除属性(' v-html ')}这一点。compiletext(节点,' innerHTML ')if(节点。hasattribute(@ click '){ let Attroval=node。getattribute(@ click’)节点。移除属性(@ click’)节点。addeventlistener(' click ',e={ this。方法[Attroval]这个。方法.bind(this)() }) } } } }),compileText(节点,类型){ let reg=/{{(.*?)}}/g,txt=node . textcontentif(reg . test(txt)).).长度1){让v=null值。拆分('。').forEach((val,i)={ v=!v?这个[val] : v[val] })返回v }else{返回这个[value] } }) } }这里代码比较多,我们拆分看你就会觉得很简单了
首先我们先遍历埃尔元素下面的所有子节点,node.nodeType===3的意思是当前元素是文本节点,node.nodeType===1的意思是当前元素是元素节点。因为可能有的是纯文本的形式,如纯双花括号就是纯文本的文本节点,然后通过判断元素节点是否还存在子节点,如果有的话就递归调用编制方法。下面重头戏来了,我们拆开看:
if(节点。hasattribute(' v-html '){ let Attroval=node。GetAttribute(' v-html ');这个。watchertask[Atrval].推送(新的观察者(节点,this,attrVal,' innerHTML ')节点。removeAttribute('v-html')}上面这个首先判断结节节点上是否有v-html这种指令,如果存在的话,我们就发布订阅,怎么发布订阅呢?只需要把当前需要订阅的数据推到观察任务里面,然后到时候在设置值的时候就可以批量更新了,实现双向数据绑定,也就是下面的操作
观察任务[键]。forEach(任务={ task.update()})然后推的值是一个看守人的实例,首先他新的的时候会先执行一次,执行的操作就是去把纯双花括号- 1,也就是说把我们写好的模板数据更新到模板视图上。最后把当前元素属性剔除出去,我们用某视频剪辑软件的时候也是看不到这种指令的,不剔除也不影响
至于看守人是什么,看下面就知道了
看守人
类观察者{构造函数(el,vm,值,类型){这。El=Elthis . VM=VM this . value=value this . type=type this。update()} update(){ this。埃尔[这个。type]=这个。虚拟机。数据[这个。值]} }之前发布订阅之后走了这里面的操作,意思就是把当前元素如:node.innerHTML='这是数据里面的值、node.value='这个是表单的数据'
那我们为什么不直接更新呢?我们还需要更新什么?不是没必要吗?其实更新,记得吗?我们需要通过调用Watcher原型上的更新方法来批量更新订阅池。
影响
在线效果地址,可以在浏览器里看效果,因为我太懒了,我就不先放gif效果图了,哈哈
完全码
完整的代码已经放在github-MyVue上了
以上就是本文的全部内容。希望对大家的学习有帮助,支持我们。