什么是vue?
官方解释:一套构建用户界面的渐进式框架。
只关注视图层,采用自底向上增量开发的设计。
它的目标是通过尽可能简单的API,去实现响应数据绑定和组合的视图组件。
vue的使用之前,我们要先引入一个vue的js文件,
两种方式:
- 去vue官网上下载vue.js到本地,使用·
<script>
标签将它引入到html文件中 - 直接引用网络上地址,CDN上的vue网络地址:https://cdn.staticfile.org/vue/2.2.2/vue.min.js
模板引擎
- 得到数据(用户产生,后续提供)
- 将数据进行动态组装
- 将组装好的内容添加到页面的指定元素中
vue做的事情简单的说,就是将data和template相结合,最后添加到挂载点上 ,再渲染到页面
1、创建一个简单的 vue实例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>使用vue</title>
<!-- 引入vue框架文件 -->
<!-- <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script> -->
</head>
<body>
<div id="app"></div>
<script>
new Vue({
// el 指定的挂载点(使用id具有唯一性,灵活性,便于识别和开发)
el: "#app",
// template 模板(最终形成UI的原始结构)
template:`<h1>{{title}}</h1>`,
// 也可以添加img标签到模板中
// template: `<img src="images/v.jpg"/>`,
// data 数据
data: {
title: "我是第一个大标题"
}
});
// 执行后,页面div中即添加了一个标题内容为"我是第一个大标题"的h1标签
</script>
</body>
</html>
2、vue挂载
使用vue需要挂载点,但有些情况是一开始不需要它,是在后面再添加上来的,称为延迟挂载
。
<!--挂载元素-->
<div id="app"></div>
<!--使用class名称的挂载点元素-->
<!--<div class="app"></div>-->
<script>
let app = new Vue({
// 开始就注明挂载点
// el: "#app",
/* el:".app",
使用class名也可以,但是calss可以重复出现并使用,如果页面元素很多、
布局复杂,就可能会出现class混用的情况,那class就不太适用了。
使用id的好处:一方面是它具有唯一性,不会出现混淆的情况;
还有就是它的灵活性。如果是循环或者嵌套循环等场景,可以动态设置和获取id。*/
template: `<div id="app">
<h1>什么是延迟挂载</h1>
</div>`
});
console.log(app);
// vue实例中,开始没有注明挂载点时,需要实例来调用$mount()去指定挂载点
app.$mount("#app");
</script>
注意:
-
el 挂载点不能是body和html
-
当实例被挂载以后,实例对象上会有一个$el的属性(属性中存的内容就是挂载的元素)
截图节选部分如下: -
vue实例上的内置属性都是以$或者_开头的
截图节选部分如下:
3、vue渲染页面
(1)template渲染
实际上vue是先把template
模板内容加载到虚拟DOM
中,再对虚拟DOM操作数据,然后将数据渲染到页面。
template模板-->虚拟DOM-->html页面
看看下面的例子:
<!--挂载点元素-->
<div id="app">
<p>app是我大哥</p>
</div>
<script>
new Vue({
// 挂载点
el:"#app",
// 生成模板,会替换掉原来的挂载点元素
template:`<div id="app">
<h1>app是我老板</h1>
<img src="images/v.jpg"/>
</div>`,
//如下写法,会报错:
//Component template should contain exactly one root element 提示模板只能有一个根节点
// template:`<div id="app">
// <h1>标题1</h1>
// <img src="images/v.jpg"/>
// </div>
// <div id="app">
// <h1>标题2</h1>
// <span>我是span标签</span>
// </div>`,
data:{}
});
</script>
如果vue实例中只有挂载点与data,没有template的情况:
<div id="app">
<p>{{name}}</p>
<p>{{sex}}</p>
<p>{{age}}</p>
</div>
<script>
// 响应数据的变化-->数据驱动视图
// 数据的变化会自动更新视图-->自动重新渲染模板
let app = new Vue({
el: "#app",
data: {
name: "布朗",
sex: "男",
age: 20
}
});
console.log(app);
</script>
在浏览器控制台上修改data中的数据,vue会自动重新渲染模板,对应的视图会更新,如下:
Vue实例对象中有一个
d
a
t
a
属
性
,
在
浏
览
器
控
制
台
中
修
改
数
据
后
,
视
图
也
会
更
新
。
比
如
修
改
a
p
p
.
data属性,在浏览器控制台中修改数据后,视图也会更新。 比如修改 app.
data属性,在浏览器控制台中修改数据后,视图也会更新。比如修改app.data.name=“约翰”,会把data中name的值以属性的形式添加到app中,如下图:
注意:
- outerHTML:设置或获取对象及其内容的html
innerHTML: 设置或获取对象的起始与结束标签内的html - 模板生成后,会替换掉挂载点
el
指定的元素 - 每一个独立的模板
有且只有一个
顶级的根节点 - 如果指定了el挂载点,却没有template,那么挂载点中的
outerHTML
将作为template;
如果有template,会优先选择template中的内容
(2)vue中render()函数
vue中内置的render()函数,可以用js语言来创建DOM
,
因为vue中是使用虚拟DOM,因此template模板时也要转译成虚拟DOM的函数,
而用render函数创建DOM,vue就省掉了这个转译的过程。
所以,用render函数来渲染页面,灵活性更高 。
<div id="app">
<h1>今天天气好晴朗</h1>
<div id="dvText">外出踏青</div>
</div>
<script>
new Vue({
el: "#app",
// render()执行就会传入一个参数createElement,这个参数就是创建虚拟DOM的工具
render(createElement) {
//传入参数,将h1中的内容替换掉
// return createElement("h1","Good afternoon!");
//传入参数,将div中的内容替换掉
// return createElement("div",{id:"dvText"},"心情好,雨天也是晴天!");
// createElement()函数:创建虚拟DOM,
// 它的三个参数分别是:标签/元素、属性/样式、内容(里面还有子元素,如下写法)
return createElement("div", {
attrs: {
id: 'app'
}
},[createElement("p",{
attrs:{
id:'pEl'
}
},"Good afternoon")]);
}
});
</script>
如下图:我们在id为app的div中创建一个p标签,并添加了条件文本内容,渲染到了页面上。
- 实际使用中我们不使用这种方法来渲染,上面的例子是来理解vue中render函数的作用与使用。
- 正如前面所说,vue是通过template来渲染页面,更简单明了,便于开发。
- 也可以使用原生js封装成函数 function createElement(tag,attrs,childrens){ //xx }; 不详说了
4、vue中的data
数据通过{{}}加载到模板中,模板加载到虚拟DOM中,
虚拟DOM会把它送到指定的挂载点元素上,从而渲染到页面上。
- 在当前模板中,
data
不需要使用this
等关键字,比如this.name,
它可以直接使用,数据都是在挂载点上生效的 - data中的数据命名,不需要使用
$
和_
开头,vue解析data后,
会把当前的data
中的数据加载到实例对象中
<div id="app"></div>
<script>
let app = new Vue({
el:"#app",
// 双大括号,又称大胡子语法
// 在vue中,我们是通过一对大括号把实例中的数据渲染到模板内容中
// {{}}双花括号,括号内直接写数据的属性名,不需要写前缀,比如this.title
template:`<div><p>{{action}}</p></div>`,
data:{
action:"与代码做斗争"
}
});
console.log(app);
</script>
5、数据劫持
当我们访问或设置对象的属性的时候,都会触发相对应的函数,
然后在这个函数里返回或设置属性的值。
我们可以在触发函数,数据发生改变时候,做点别的事情,这就是“劫持”。
在Vue中其实就是通过Object.defineProperty()
来劫持对象属性的setter和getter操作,
起到一个监听器的作用,当数据发生变化的时候发出通知。
<div id="app">
<h1>{{name}}</h1>
</div>
<script>
// 手动方式更新视图
let app = document.querySelector("#app");
function render(){
// 拼接另一个属性age
app.innerHTML = obj.attr+"-"+obj.age;
}
let obj = {attr:"cool"};
render();
// 浏览器控制台修改数据,控制台数据修改了,但是页面上的数据没有实时更新
/* obj.attr="beautiful";
"beautiful"
obj.attr = 10;
10
*/
// obj.attr = "beautiful";//手动更新一下数据
// render();//再次渲染页面,页面数据更新了
//再次在浏览器控制台修改数据,再调用render()方法后,页面数据更新了
/* obj.attr="lovely";
"lovely"
render();
undefined
*/
// vue的方式更新视图
// vue就是通过监听,将这个数据手动修改与更新的过程自动化了
// defineProperty()用来监听数据的属性(只能监听单个属性,新增属性监听不了,需要再写一次)
let $data = {attr:"cool"};//$data替代obj
// // let $data = obj;//会报错Maximum call stack size exceeded
Object.defineProperty(obj,"attr",{
set(newValue){
// obj.attr = newValue;//这样写就成了死循环,attr永远跳不出来
$data.attr = newValue;//每次修改的是冒充的对象$data
render();
},
get(){
return $data.attr;//获取时覆盖原来的值
}
});
// 浏览器控制台修改数据,页面同时更新了
/* obj.attr="instersting";
"instersting"
obj.attr="cute";
"cute"
*/
// 比如如果有别的属性age,需要再写一次监听,不然会出现更新其中一个,另一个属性不会更新的问题
Object.defineProperty(obj,"age",{
set(newValue){
$data.age = newValue;
render();
},
get(){
return $data.age;
}
});
/* obj.attr="tom"
"tom"
obj.age=20;
20 */
</script>
补充:
- vue3.0加入了Proxy对象,去解决只能监听单一属性的问题,暂时没有使用文档
为了解决Object.defineProperty()只能监听单个属性的问题,vue中实例提供了一个set()方法
看一下案例
<div>
<h1>name:{{obj.name}}</h1>
<h1>age:{{obj.age}}</h1>
</div>
<script>
let app = new Vue({
el:"#app",
data:{
obj:{name:"汤姆"}
}
});
</script>
修改obj的name属性值,页面会随之更新;而修改属性age的值,页面却没有变化。截图如下:
分析:因为data中我们只监听了name属性,而age没有被监听。
我们再次修改name的值,age修改后的值才会显示出来,就是说age是随着name的改变而变化的。而单独修改age值,页面不受影响,截图如下:
我们使用vue实例提供了方法$set(),这样就可以添加age属性,从而监听到age的值的变化
<script>
let app = new Vue({
el:"#app",
data:{
obj:{name:"汤姆"}
}
});
// 使用$set()添加age
app.$set(app.obj,"age",20);
</script>
调用$set()后,看看,age属性值也可以被监听到了,控制台做出修改,页面会实时更新了!