1.Vue与模板
vue是如何使用的:
- 编写页面模板
- 创建Vue实例
- 在Vue构造函数中提供:data、methods、computed...
- 将Vue挂载到页面中(mount)
下面是一个代码实例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <!-- 第一步:写模板 --> <div id="root"> <h1>姓名:{{name}}——年龄:{{age}}</h1> </div> <script> // 第二步:创建Vue实例 let app=new Vue({ el:'#root', data:{ name:'xxx', age:14 } }) // 第三步:挂载。这种用法的挂载在vue.js中帮我们实现了 </script> </body> </html>
2.数据驱动模型
Vue的执行流程:
- 获得模板:模板中有预留的坑(如{{}}、:等)
- 利用Vue构造函数中所提供的数据来填补预留的坑,就可以在页面上显示标签 了
- 将标签替换页面中原来有坑的标签
Vue利用我们提供的数据和页面中的模板,生成了一个新的HTML标签,替换到了页面中放置模板的位置。
比如:在上面那个例子中打印那个root标签:
<script> console.log(root); let app=new Vue({ el:'#root', data:{ name:'xxx', age:14 } }) console.log(root); </script>
控制台结果:
- 此时如果将鼠标悬浮在第二次打印的root上面,页面上会高亮表示选中的是当前的标签
- 但是将鼠标悬浮在第一次打印的结果上没有高亮,表明创建Vue实例之后的root的标签已经不是页面刚加载时的那个标签了
3.一个简单的模板填充数据的实例:
这个部分的作用是把页面模板上带有花括号的内容全部替换成具体的数据:<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <!-- 第一步:写模板 --> <div id="root"> <div> <div> <h1>姓名:{{name}}——年龄:{{age}}</h1> </div> </div> <h2>姓名:{{name}}</h2> <h2>年龄:{{age}}</h2> </div> <script> let r = /{{(.+?)}}/g /** * 步骤拆解: * 1.拿到模板 * 2.拿到数据(data) * 3.将数据与模板结合,得到的是HTML元素(DOM元素) * 4.放到页面中 * */ // 1 let tempNode = document.getElementById('root') // 2 let data = { name: 'xlx', age: 26 } // 3.将数据放到模板中:一般都是使用递归 // 在这个案例中,template是一个DOM元素 // 在真正的VUe源码中是将DOM元素转换成字符串模板 -> 转换成抽象语法树 -> 转换成虚拟DOM(VNode) -> 转换成真正的DOM function compiler(template, data) { // 这个函数,把花括号里面的数据用data里面所对应的属性进行替换 // 把子元素中所有带双花括号的元素取出来 let childNodes = template.childNodes // 取出子元素 for (let i = 0; i < childNodes.length; i++) { let type = childNodes[i].nodeType // nodeType表示这个节点的类型:1表示元素节点;3表示文本节点(不同浏览器不同,这里只需要记住这两个) if (type === 3) { // 文本节点,可以判断里面是否有 {{}} 插值 let txt = childNodes[i].nodeValue // nodeValue该属性只有文本节点才有意义 // 有没有{{}}呢 txt = txt.replace(r, function (_, g) { // replace方法,使用正则匹配了一次,这个函数就会被调用一次。return的值就是替换的匹配到的值 // 参数一:表示匹配到的内容 // 参数二:表示正则中的第n组:g.trim()表示写在双花括号里面的东西 let key = g.trim(); let value = data[key] // 将{{ xxx }}用这个值(data中对应的值)替换 return value }) // 注意:txt现在和DOM元素是没有关系的,需要将修改后的值放回去 childNodes[i].nodeValue = txt } else if (type === 1) { // 元素节点,考虑有没有子元素,是否需要将其子元素进行判断是否要插值 compiler(childNodes[i], data) // 递归处理 } } } // 我们此时是没有生成新的template,所以这里看到的是直接在页面中就更新的数据,因为DOM是引用类型 // 但是我们这么处理的话,原来带{{}}的模板就没有了。无法再更新了
// 利用模板生成一个需要被渲染的HTML标签(准·真正在页面中显示的标签) let generateNode = tempNode.cloneNode(true) // 注意这里是DOM元素,可以直接这么用 console.log(1, tempNode); compiler(generateNode, data) console.log(2, generateNode); // 4.将渲染好的HTML加到页面当中 root.parentNode.replaceChild(generateNode, root) // 到此为止:上面的思路有比较大的问题 // 1.Vue使用的是虚拟DOM,而这里用的是真实的DOM // 2.只考虑了单属性{{ name }},而Vue中大量的使用了层级({{ child.name }}) // 3.代码没有整合 </script> </body> </html>
页面结果如下:
说明:这个实现的大致理论: