Vue基础及原理
Vue.js 是用于构建交互式的 Web 界面的库。提供了 MVVM 数据绑定和一个可组合的组件系统,具有简单、灵活的 API。
初识Vue.js
Vue.js 是用于构建用户界面( UI页面,即静态页面 )的渐进式框架(诱导的方式)
- 核心功能: 模板引擎 {{ 数据 }} 便于页面组装数据
- 组件: 页面的复用性
- 带前端路由
- 状态管理器: 管理数据 (具有伸缩性)
- 自动化构建
<!-- 引入Vue框架 网络地址 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">{{title}}</div>
<script>
new Vue({
el:"#app",
// 别称:双花括号语法,大胡子语法
template:`
<h1>{{title}}</h1>
`,
data:{
title:"生活不易"
}
})
</script>
{{ }} 模板引擎
- 得到一批数据(后端提供,用户产生…)
- 将数据动态的组装
- 将组装好的内容添加到页面 指定元素
el 挂载点
<div id="app"> </div>
el : " #app "
template 模板
预先生成模板(最终形成 UI页面 原始结构)
data 数据
存放一些来自后端或者用户的数据
Vue.js 帮助我们做的
将 data 和 template 相结合,最后添加到挂载点
- 模板生成后,会替换掉 挂载点(指定的元素)
// 没有 data
new Vue({
el:"#app",
// 防止被替换 直接外面包裹一层
template:`
<div id="app">
<h1>不被替换的方法</h1>
</div>
`
})
- 每一个独立的模板 有且只能有一个顶级的根节点
new Vue({
el:"#app",
// 别称:双花括号语法
template:`
<div id="app">
<h1>不被替换的方法</h1>
</div>
<div id="app">
<h1>不被替换的方法</h1>
</div>
`
})
- 指定el 且没有 template 那么 el 中的 outerHTML 将作为 template
如果有的话,优先选择 template 中的内容
( outerHTML 包含的内容 :文本 + 标签 )
new Vue({
el:"#app"
})
Vue渲染过程
template => VDOM(虚拟dom) => html
Vue 使用灵活化
render(Vue函数渲染)
研究 render ( ) 实际上研究的是,其中的回调函数;
回调函数 creatElement 的实现,是在 虚拟Dom 中完成的,完成之后添加到 HTML页面
render 替代了 template 使Vue的使用,变得更加灵活
但与此同时,写法变得复杂
实际使用中,仍然是 template 为主
- 单层标签实现
// 单层实现 生成 #app
new Vue({
el: "#app",
// render 为固定名称 替代了 template 变得更加灵活
render(creatElement) {
return creatElement("div","2020");
}
})
// creatElement 参数
{
tag:"h1",
attrs:{id:"app"},
children: "文本"
}
- 双层标签实现
// 两层嵌套 生成 #app 及 h1
new Vue({
el: "#app",
// 固定名称
render(creatElement) {
return creatElement("div",{ attrs : {id:'app'} },[
creatElement("h1","2020")
]);
}
})
// creatElement 参数
{
tag:"h1",
attrs:{id:"app"},
children:[
{
tag:"h1",
children:["文本","文本"] / "文本"
}
]
}
el 延迟挂载
使得挂载灵活化
<div id="app"></div>
有些情况下,在实例化 Vue 并时不明确 被替换的元素 ( 挂载点 )
希望在使用的时候才去替换
// 延迟挂载 挂载灵活化
let app = new Vue({
template:`
<div id="app">
<h1>不被替换的方法</h1>
</div>
`
})
指定挂载点
- el挂载点不能是 html 和 body
- 当实例被挂载以后,实例对象就会有一个 $el 的属性,
属性中存的内容就是挂载的元素 - vue实例上的内置属性都是以 $ 或者 _开头的
app.$mount("#app");
data
- 在当前模板中可以直接使用(不需要去使用 this类)
- data 中的数据命名 不要使用 $ 或者 _ 开头
因为 Vue 解析 data 以后,会把当前data中的数据加载到实例对象中
( 极有可能与 Vue 自身携带的属性会冲突 )
<div id="app">
<h1>{{name}}</h1>
</div>
let app = new Vue({
el: "#app",
taemplate: `
<div id="app">
<h1>{{name}}</h1>
</div>
`,
data: {
name: "开课了"
}
})
Vue 视图更新
数据响应式,用数据来驱动视图,数据的变化会自动更新视图( 自动重新渲染模板 )
Vue 实现这一功能的原理是:数据劫持监听
- HTML
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<h1>{{name}}</h1>
</div>
- JS代码
let app = new Vue({
el:"#app",
data:{
name:"开课了"
}
});
- 效果图
修改数据体验 数据驱动视图
改变数据 页面就会发生改变,
为了更好的展示效果,建议在浏览器端的控制台操作
同样修改也可以使用 app.$data.name = "是时候重拳出击了";
数据劫持
正常情况下,更新视图需要不停的去渲染页面
<div id="app">
<h1>{{name}}</h1>
</div>
<script>
let app = document.querySelector("#app");
function render(){
console.log("数据驱动视图…");
app.innerHTML = obj.name + "/" + obj.height;
}
// 修改 obj 中的属性,然后调用 render 方法 不停的重复
let obj = {
name:"兟"
}
render();
</script>
但是 Vue 直接实现了自动渲染,我们需要做的就是修改数据而已
Vue 实现视图更新依靠的便是 数据劫持
依赖 defineProperty 方法去实现
let $data = JSON.parse(JSON.stringify(obj));
// 监听 然后修改替代品 返回替代品的数据 用来渲染页面
Object.defineProperty(obj,"name",{
set(newValue){
// 不能写 obj.name 不然就是死循环
// 只能借用冒充数据 保持一致 $data
$data.name = newValue;
render();
},
get(){
return $data.name;
}
})
原因是: defineProperty 方法,只能监听对象中的某一指定属性
对于新的属性只能再次使用 defineProperty 方法去监听新属性
Object.defineProperty(obj,"height",{
set(newValue){
$data.height = newValue;
render();
},
get(){
return $data.height;
}
})
完善视图更新
Vue 3.0提供了新的方法,去实现监听多个对象属性
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<h1>x:{{obj.x}}</h1>
<h1>y:{{obj.y}}</h1>
</div>
<script>
let app = new Vue({
el:"#app",
data:{
obj:{
x:1
}
}
})
// 监听 x
// app.obj.y = 12; // => 页面无变化
// app.obj.x = 10; // => 页面变化,连带更新后的 y
// 新增的方法
// 实质上等同于 再写一遍 Object.defineProperty
app.$set(app.obj,'y',2)
</script>
特殊情况
去尝试监听数组
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<h3>{{arr}}</h3>
</div>
<script>
let app = new Vue({
el:"#app",
data:{
arr:[1,2,3]
}
})
app.arr.push(100) // 视图更新了
</script>
默认不监听数组,但是 Vue 对数组的 push、pop等方法 进行了监听拦截