目录
简介
Vue基本渲染-插值和数据模型
MVVM
生命周期
模版语法
条件渲染
v-if
编辑
v-show
列表渲染
key
style绑定
class绑定
简介
Vue是一套用于构建用户界面的渐进式框架。与其他大型框架不同的是,Vue被设计为可以自底向上逐层应用。Vue的核心库只关注视图层,不仅容易上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue也完全能够为复杂的单页应用提供驱动。用来做单页面应用--index.html,页面跳转用的vue插件路由来实现跳转。
Vue基本渲染-插值和数据模型
//1-Vue基本渲染-插值
//代码
window.onload = function () {
// 创建vue实例,vue实例要与模板(DOM)绑定
let vm= new Vue({
el: "#app",
data: {// 数据模型
msg:'hello world'
},
// 函数
methods: {
changeData(){
if(this.msg==='hello world'){
// 更改数据模型中的数据
// 获取数据模型中的数据
// 在vue实例内访问vue实例身上的属性和方法
this.msg='你好我是修改后的值'
}else{
this.msg='hello world';
}
}
},
})
}
//html代码
<!-- 以前把msg作为元素文本的,获取dom节点,绑定事件,dom.innerText=msg-->
<div id="app">
<!-- 在模板内访问vue实例中数据模型中的数据 插值 -->
<!-- 基本渲染 插值 -->
{{msg}}
<p>{{msg}}</p>
<!-- 点击按钮 改变数据模型中的数据msg变量 -->
<button @click='changeData'>点我修改数据模型msg数据</button>
</div>
//数据模型更改,引发了vm驱动
MVVM
MVVM 模式,顾名思义即 Model-View-ViewModel 模式。
mvvm介绍: m指model服务器上的业务逻辑操作,v指view视图(页面),vm指ViewModel模型跟视图间的核心枢纽,比如vue.js
可以将上图中的
DOM Listeners
和Data Bindings
看作两个工具,它们是实现双向绑定的关键。从View侧看,ViewModel中的
DOM Listeners
工具会帮我们监测页面上DOM元素的变化,如果有变化,则更改Model中的数据;从Model侧看,当我们更新Model中的数据时,
Data Bindings
工具会帮我们更新页面中的DOM元素。
//2.数据模型
let vm=new Vue({
el:'#app',
data:{
msg:'高校优质男',
time:new Date()
},
methods:{
sayName(){
console.log(this.name)
},
}
})
// 每隔一秒重新查询一次时间
setInterval(()=>{
vm.time=new Date()
},1000)
// 查看vue实例对象
console.log(vm)
生命周期
vue实例创建到虚拟dom产生再到数据绑定监听数据渲染以及销毁的整个过程
生命周期的第一步首先是创建vue实例,并且进行初始化。
vue实例初始化阶段
beforeCreate
在初始化的时候调用了beforeCreate,完成了vue实例的生命周期相关属性的初始化以及事件的初始化。这个时候还不能访问数据模型中的data和methods中的方法。
created
在初始化完毕之后,完成vue的数据注入以及数据监听操作,该构造的执行意味着vue实例创建完毕,可以进行data数据模型和和methods方法的访问
vue实例挂载阶段
beforeMount
在created之后,vue会判断实例中是否含有el属性,如果没有vm.$mount(el),接着会判断是否含有template属性,如果有将其解析为一个render function,如果没有将el指定的外部html进行解析。这里只完成了模板的解析但是数据并没有绑定到模板中。
mounted
创建vm.$el替换el,实际上完成的是数据绑定操作,在其间执行了render函数,将模板进行了解析,将数据进行了动态绑定
vue实例更新阶段
beforeUpdate
更新虚拟dom节点
updated
完成了页面的重新渲染
vue实例销毁阶段
beforeDestroy
销毁之前调用,此时可以访问vue实例
destroyed
完成了监听器,子组件,事件监听等移除,销毁vue实例对象。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.6/axios.js"></script>
</head>
<body>
<!-- 模版 视图层 -->
<div id="app">
<!-- 采用ref代替id ref表示dom的引用 可以通过ref属性找到dom元素 -->
<div ref="box">{{msg}}</div>
</div>
<script>
let vm = new Vue({
// 使用el属性和模版进行绑定
el: '#app',
// 数据模型 存放vue变量
data: {
msg: 'hello Vue2'
},
// vue实例中提供了template模板 就把template作为模板编译,使用render函数渲染
// template:`
// <h1>{{msg}}</h1>
// `,
methods: {
// 异步请求 查询所有轮播图 axios
async findAll() {
let res = await axios.get('http://121.199.0.35:8888/index/carousel/findAll');
console.log(res);
}
},
/**
* 生命周期
* beforeCreate实例初始化之前 初始化默认事件和生命周期
* created 实例初始化完成 可以访问数据模型data和methods中的方法 是异步请求可以最早
*/
beforeCreate() {
console.log('实例初始化之前 初始化默认事件和生命周期', this.msg);
},
created() {
console.log('实例初始化完成 初始化完成响应式数据和methods方法', this.msg);
// this.findAll();
},
/**
* 实例挂载阶段 与模板绑定阶段
* beforeMount 实例挂载之前 查看有没有el选项,有的话查看有没有template选项
* 没有template选项,将el外部的html元素作为模板 此时访问不到dom元素
* mounted 实例挂载完成 vm创建$el代替el完成模板编译 此时可以访问dom元素 渲染图表 可以发送异步请求
*/
beforeMount() {
console.log('实例挂载之前 此时访问不到dom节点', this.$refs.box, '获取ref引用对应的dom元素')
},
// 也可以手动提供render函数编译模板
// render(createElement) {
// return createElement('h2', {}, this.msg1)
// },
mounted() {
console.log('实例挂载完成 此时可以访问dom节点', this.$refs['box'])
},
/**
* 实例更新阶段 只要响应式数据发生更改 生命周期就会被触发
* beforeUpdate 实例更新前 此时更改了数据,数据是最新,dom中数据还是原始数据,dom还未重新更新
* updated 实例更新后 此时dom中数据就是最新数据 dom重新被编译到模板中
*
* vue机制 nextTick 异步加载dom 更新dom 数据更改 dom用到该数据不会立马更新 dom更新存放在回调函数中
* 会在下一次回调函数中完成更新
*/
beforeUpdate() {
console.log('实例更新前', this.$refs.box.innerHTML, this.msg);
},
updated() {
console.log('实例更新完成', this.$refs.box.innerHTML, this.msg);
},
/**
* 实例销毁阶段生命周期
* beforeDestroy 实例销毁之前 依旧可以修改vue实例响应式数据
* destroyed 实例销毁完成 销毁了监听器 子组件 和事件监听 无法修改vue实例响应式数据 不会触发更新阶段生命周期
*/
beforeDestroy() {
console.log('实例销毁之前', this.msg);
},
destroyed() {
console.log('实例销毁完成', this.msg);
}
});
setTimeout(() => {
// 手动销毁实例
vm.$destroy()
}, 8000);
// 如果没有el属性 可以使用$mount和模板进行绑定
// vm.$mount('#app');
// setTimeout(()=>{
// vm.msg = 'hello world'
// },1000)
</script>
</body>
</html>
模版语法
介绍:
vue使用了基于HTML的模板语法,允许开发者声明式地将DOM绑定至底层Vue实例的数据。所有 Vue的模板都是合法的 HTML,所以能被遵循规范的浏览器和HTML解析器解析。在底层的实现上,Vue 将模板编译成虚拟 DOM 渲染函数。结合响应系统,Vue 能够智能地计算出最少需要重新渲染多少组件,并把 DOM 操作次数减到最少。如果你熟悉虚拟 DOM 并且偏爱 JavaScript 的原始力量,你也可以不用模板,直接编写渲染函数及render,使用可选的 JSX 语法(react采用的就是jsx语法)。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
</head>
<body>
<!-- 模版 -->
<div id="app">
<!-- 1.Mustache语法 双花括号 文本插值 -->
{{msg}}
<!-- 2.使用v-once 进行一次性插值 后续该vue变量改变 执行一次性插值的dom元素不会改变 -->
<div v-once>{{msg}}</div>
<!-- 3.使用v-html 识别代码片段 -->
<!-- {{content}} 无法将字符串中标签解析 -->
<div v-html="content"></div>
<!-- 4.1给标签绑定变量 使用v-bind进行绑定 无法使用{{}} -->
<!-- <div v-bind:title="title">我是一个块级元素</div> -->
<!-- 4.2绑定变量 简写为: -->
<div :title="title">我是一个块级元素</div>
<!-- 5.1给标签绑定事件 使用v-on:事件类型 -->
<!-- <button v-on:click="handler">点击我</button> -->
<!-- 5.2给标签绑定事件 简写为@ -->
<button @click="handler">点击我</button>
<!-- 6.{{js表达式}} -->
{{Boolean(str)}}
{{str.split(",").reverse()}}
{{str?'string':'null'}}
<!-- {{if(str){console.log(str)}else{console.log('null')}}} -->
</div>
<script>
let vm = new Vue({
// el:'#app',
// 数据模型
data:{
msg:'hello vue2',
str:'hello',
content:'<p>文章标题</p><article>文章内容<a href="#">百度一下</a></article>',
title:'我div标签的提示说明'
},
methods:{
handler(){
console.log('我被点击了');
}
},
});
// vue实例与模版进行绑定
vm.$mount('#app');
setTimeout(()=>{
vm.msg = 'hello world'
},1000)
</script>
</body>
</html>
条件渲染
v-if
v-if(可以单独使用),表达式为true的时候渲染使用v-if属性的元素,否则使用v-else渲染
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 条件渲染 v-if v-else-if v-else 或者使用v-show -->
<div v-if="type==='tel'">
<form>
<label for="tel">电话:</label>
<input type="text" id="tel" placeholder="请输入电话号码">
</form>
</div>
<div v-else-if="type==='email'">
<form>
<label for="email">邮箱:</label>
<input type="text" id="email" placeholder="请输入邮箱">
</form>
</div>
<div v-else>错误</div>
<button @click="toggle">切换</button>
<div v-show>显示内容</div>
</div>
<script>
new Vue({
el:'#app',
data:{
type:'tel',
isShow:false,
},
methods:{
toggle(){
if(this.type==='tel'){
this.type='email'
}else{
this.type='tel'
}
}
},
});
</script>
</body>
</html>
从结果可以看出:
v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做;直到条件第一次变为真时,才会开始渲染条件块。
v-if 有更高的切换开销。
v-if对应的是元素/标签的添加或者删除
满足条件添加元素 不满足条件删除元素
v-show
v-show(切换css样式中display属性),频繁切换css样式,使用v-show
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 条件渲染 v-if v-else-if v-else 或者使用v-show -->
<div v-show="type==='tel'">
<form>
<label for="tel">电话:</label>
<input type="text" id="tel" placeholder="请输入电话号码">
</form>
</div>
<div v-show="type==='email'">
<form>
<label for="email">邮箱:</label>
<input type="text" id="email" placeholder="请输入邮箱">
</form>
</div>
<button @click="toggle">切换</button>
<div v-show>显示内容</div>
</div>
<script>
new Vue({
el:'#app',
data:{
type:'tel',
isShow:false,
},
methods:{
toggle(){
if(this.type==='tel'){
this.type='email'
}else{
this.type='tel'
}
}
},
});
</script>
</body>
</html>
从结果可以看出:
v-show 不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
v-show 有更高的初始渲染开销。
v-show对应的是元素的CSS样式中的display属性
满足条件对应的是元素的显示 display:block
不满足条件对应的是元素的隐藏 display:none
v-show用于频繁的切换css样式
列表渲染
用于将列表数据进行渲染。v-for 指令需要使用 item in items 形式的特殊语法,其中 items 是源数据数组,而 item 则是被迭代的数组元素的别名。
key
Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做可以使 Vue 变得非常快。但是有些时候,我们却不希望vue复用,这时候Vue 为你提供了一种方式来表达“这两个元素是完全独立的,不要复用它们”。只需添加一个具有唯一值的 key
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script> -->
<script src="../vue.js"></script>
</head>
<body>
<div id="app">
<ul>
<!-- <li v-for="(item,index) in animal">
{{item}}---{{message}}---{{index}}
</li> -->
<!-- <li v-for="(item,index) of animal">
{{item}}---{{message}}---{{index}}
</li> -->
<!-- <li v-for="(value,key,index) in obj">
{{key}}---{{value}}---{{index}}
</li> -->
<li v-for="(value,key,index) of obj":key="index">
{{key}}---{{value}}---{{index}}
</li>
</ul>
</div>
<script>
new Vue({
el:'#app',
data:{
message:'消息',
animal:['猴子','大象','老虎'],
obj:{
name:'terry',
age:18,
gender:'male'
}
},
methods:{},
})
</script>
</body>
</html>
style绑定
操作元素的class列表和内联样式是数据绑定的一个常见需求,因为它们都是attribute,所以我们可以用v-bind处理它们:只需要通过表达式计算出字符串结果即可。不过,字符串拼接麻烦且易错。因此,在将v-bind用于class和style时,Vue做了专门的增强。表达式结果的类型除了字符串之外,还可以是对象或数组。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<style>
</style>
</head>
<body>
<div id="app">
<!-- style绑定 动态绑定 -->
<div :style="{color:current}">{{msg}}</div>
<div :style="styleObj1">{{msg}}</div>
<div :style="[styleObj1,styleObj2]">{{msg}}</div>
</div>
<script>
new Vue({
el:'#app',
data:{
msg:"hello Vue2",
current:'red',
styleObj1:{
fontSize:'24px',
backgroundColor:"pink",
},
styleObj2:{
width:'100px',
height:'100px',
}
},
methods:{},
})
</script>
</body>
</html>
class绑定
操作元素的class列表和内联样式是数据绑定的一个常见需求,因为它们都是attribute,所以我们可以用v-bind处理它们:只需要通过表达式计算出字符串结果即可。不过,字符串拼接麻烦且易错。因此,在将v-bind用于class和style时,Vue做了专门的增强。表达式结果的类型除了字符串之外,还可以是对象或数组。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<style>
.four{
border: 1px solid cyan;
}
.active{
color: red;
font-size: 24px;
}
.error{
background: blue;
}
</style>
</head>
<body>
<div id="app">
<!-- 动态绑定类名 -->
<div class="four" :class="{active:isActive,error:hasError}">{{msg}}</div>
<div class="four" :class="toggle">{{msg}}</div>
<div class="four" :class="[isActive1,hasError1]">{{msg}}</div>
</div>
<script>
new Vue({
el:'#app',
data:{
isActive:true,
hasError:false,
isActive1:'active',
hasError1:'error',
toggle:{
active:false,
error:true,
},
msg:"hello Vue2",
},
methods:{},
})
</script>
</body>
</html>
【面试题:为什么在大型项目中data是一个函数而不是一个对象】
组件是一个可复用的实例,当你引用一个组件的时候,组件里的data是一个普通的对象,所有用到这个组件的都引用的同一个data,就会造成数据污染。
不使用return包裹的数据会在项目的全局可见,会造成变量污染;
使用return包裹后数据中变量只在当前组件中生效,不会影响其他组件。
当一个组件被定义, data 必须声明为返回一个初始数据对象的函数,因为组件可能被用来创建多个实例。如果 data 仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象!通过提供 data 函数,每次创建一个新实例后,我们能够调用 data 函数,从而返回初始数据的一个全新副本数据对象。