简介
什么是Vue?
一套用于构建用户界面的渐进式JavaScript框架。将数据转变成用户可看到的界面。
什么是渐进式?
Vue可以自底向上逐层的应用
简单应用:只需一个轻量小巧的核心库
复杂应用:可以引入各式各样的Vue插件
Vue的特点是什么?
1.采用组件化模式,提高代码复用率、且让代码更好维护。
2.声明式编码,让编码人员无需直接操作DOM,提高开发效率。
3.使用虚拟DOM+优秀的Diff 算法,尽量复用DOM节点
Vue官网
vue2
介绍 — Vue.js
vue3
Vue.js - 渐进式 JavaScript 框架 | Vue.js
Vue2-html文件中写vue
下载安装
开发版本比较大,生产版本较小。
开发时推荐引入开发版本的vue,有提示。
我们下载下来源码并引用,甚至可用修改源码。
下载Vue开发者工具
参考:vue devtools在谷歌浏览器安装使用,附vue,vue3devtools下载资源_vue3.js tools 谷歌_…咦的博客-CSDN博客
学习vue2,可参考vue2的文档API — Vue.js
外:shift+点击网页刷新,为强制刷新。
外:vscode的live server运行html,网页除了输入http://127.0.0.1:5h500/http://127.0.0.1:5500/Vue/Vue.htmlhttp://127.0.0.1:5500/还可输入http://127.0.0.1:5500/,然后选中文件夹
可在vsCoder中安装一个Vue 3 snippets插件。 写vue代码回有提示补全。
演示代码:
目录结构
html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>初识Vue</title>
<script type="text/javascript" src="../js/vue.js">
</script>
</head>
<body>
<!-- 总结:
初识Vue:
1.想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象;
2.root容器里的代码依然符合html规范。只不过混入了一些特殊的Vue语法;
3.root容器里的代码被称为【Vue模板】;
4.Vue实例和容器是一一对应的;
5.真实开发中只有一个Vue实例,并且会配合着组件一起使用;
6.{{xxx}}中的xxx要写js表达式,且xxx可以自动读取到data中的所有属性;
7.一旦data中的数据发生改变,那么页面中用到该数据的地方也会自动更新;
-->
<!-- 准备好一个容器 -->
<div id="root">
<h1>hello,kdy</h1>
<!-- {{}}中的需要为一个js表达式(表达式最终计算出一个值的),而不是js代码 -->
<p>{{name.toUpperCase()}}--{{new Date()}}</p>
</div>
<p>{{name}}</p><!--//容器外,data无效-->
<script type="text/javascript">
Vue.config.productionTip=false
// 在配置下方写vue实例
/*const x = */new Vue({
el:"#root", //element元素,让vue实例和容器之间建立联系,指定当前实例为哪个容器服务.里面传递选择器,可id可class.,若class就".root"
data:{ //data中用于存储数据,数据供el所指定的容器去使用。
name:"kdy"
}
})
</script>
</body>
</html>
注意:vue实例和容器之间是一对一的:若两个class为root容器对于一个绑定.root的vue实例,则第二个容器中不生效。若一个id为root的容器绑定两个new Vue的cl为“#root”的实例,则第二个new的vue实例不生效。
模板语法
1、插值语法{{}}:位于标签体中
2、指令语法v-bind:位于标签属性
代码演示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>模板语法</title>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--
Vue模板语法有2大类:1.插值语法:
功能:用于解析标签体内容。
写法:{{xxx}},xxx是js表达式,且可以直接读取到data中的所有属性。2.指令语法:
功能:用于解析标签(包括:标签属性、标签体内容、绑定事件.....) 。
举例:v-bind:href="xxx”或简写为:href="xxx",xxx同样要写js表达式,
且可以直接读取到data中的所有属性。
备注: Vue中有很多的指令,且形式都是: v-????,此处我们只是拿v-bind举个例子。
-->
<div id="app">
<p>{{message}}</>
<p>{{user.name}}</>
<p>{{user.age}}</><br/>
<!-- 指令语法v-bind: 可指定任何一个属性-->
<a v-bind:href="url">百度</a>
<div :x="hello"></div>
</div>
<script type="text/javascript">
new Vue({
el:"#app",
data:{
message:"插值语法",
url:"http://www.baidu.com",
hello:"你好",
user:{
name:"王五",
age:20
}
},
})
</script>
</body>
</html>
数据绑定
单向数据绑定v-bind:,data->模板页面
代码案例 数据绑定.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>数据绑定</title>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--
Vue中有2种数据绑定的方式:
1.单向绑定(v-bind):数据只能从data流向页面。
2.双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向data。
备注:
1.双向绑定一般都应用在表单类元素上(如: input、select等)
2.v-model:value可以简写为v-model,因为v-model默认收集的就是value值。
-->
<div id="app">
单向数据绑定:<input type="text" v-bind:value="msg"/><br/>
双向数据绑定:<input type="text" v-model:value="msg2"/><br/>
双向数据绑定:<input type="text" v-model="msg2"/>
<!-- 如下代码是错误的,v-model只能绑定在表单类的元素(输入元素)上
input\单选框\多选框\select框\多行输入
-->
<!-- <h2 v-model:x="msg2">你好啊</h2> -->
</div>
<script type="text/javascript">
new Vue({
el:"#app",
data:{
msg:"hello123",
msg2:"hello123"
},
})
</script>
</body>
</body>
</html>
el与data的两种写法
代码展示: el与data的两种写法.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>el与data的两种写法</title>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--
data与el的2种写法
1.el有2种写法
( 1).new Vue时候配置el属性。
(2).先创建Vue实例,随后再通过vm. $mount( ' #root ')指定el的值。
2.data有2种写法
(1).对象式(2).函数式
如何选择:目前哪种写法都可以,以后学习到组件时,data必须使用函数式,否则会报错。
3.一个重要的原则:
由Vue管理的函数,一定不要写箭头函数,一旦写了箭头函数,this就不再是Vue实例了。
-->
<div id="root">
<h1>你好,{{name}}</h1>
</div>
<script type="text/javascript">
/* const v = new Vue({
//el:"#root",
data:{
name:"王五"
}
})
console.log(v)//打印出vue实例.发现有很多$开头的内容,这些$开头的内容就是给程序员使用的./
//el就可通过v.$mount("#root"),这种方式比较灵活.
v.$mount("#root")
*/
new Vue({
el:"#root",
//data的第一种写法:对象式
/*data:{
name:"王五"
},*/
//data的第二种写法:函数式 以后学习组件的时候,必须使用该函数式的data
data:function(){
console.log(this)//此处的this是vue实例对象
return{
name:"王六"
}
},
/*data函数式不能写箭头函数,以下写法是错误的,必须老老实实的写上面的function的这种.
data:()=>{
console.log(this)//箭头函数由于没有自己的this,就找到了最外层的data即windows
}*/
})
</script>
</body>
</html>
MVVM模型
vue参考了MVVM:
1.M:模型(Model) :对应data中的数据
2.V:视图(View):模板
3.VM:视图模型(ViewModel) : Vue 实例对象
文档中常用vm代表vue实例。
vm实例中的所有东西都可写在{{}}中
代码演示:vue中的MVVM.html:
<!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 type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--
观察发现:
1.data中所有的属性,最后都出现在了vm身上。
2.vm身上所有的属性及 Vue原型上所有属性,在Vue模板中都可以直接使用。
-->
<div id="root">
<p>{{name}}</p>
<!-- vue实例中的东西都可在{{}}中 -->
<P>{{$options}}</P>
<P>{{$emit}}</P>
<!-- view -->
</div>
<script type="text/javascript">
const vm = new Vue({ // ViewModel
el:"#root",
data:{// model
name:"张三"
}
})
console.log(vm)//data中写的内容会出现在vm上,也就是vue实例上.
</script>
</body>
</html>
回顾js的Object.defineproperty方法
代码演示:Object.defineproperty.html
<!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>
<script type="text/javascript">
let number = 18;
let person={
name:"张三",
sex:"男"
}
Object.defineProperty(person,'age', { //给person增加一个属性
//value:18,
//enumerable:true, //控制属性是否可以枚举,默认值是false
//writable:true, //控制属性是否可以被修改,默认值是false
//configurable:true, //控制属性是否可以被删除,默认值是false
//当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值
get:function(){ //get:function()也可简写为get()
console.log('有人读取age属性了')
return number
},
set(value){
console.log('有人修改了age属性,且值是',value)
number=value
}
})
console.log(person)
console.log(Object.keys(person))
for(let key in person){
console.log('@',person[key])
}
</script>
</body>
</html>
运行后在f12控制台中person.age和person.age = 150这样设置。
数据代理
代码演示:何为数据代理.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>何为数据代理</title>
</head>
<body>
<script type="text/javascript" >
let obj = {x:100}
let obj2 = {y:200}
Object.defineProperty(obj2,'x',{
get(){
return obj.x
},
set(value){
obj.x = value
}
})
</script>
</body>
</html>
运行后在f12控制台中obj.x和obj2.x和其set。
就是通过vm读取或写入data中的数据:
vm将data中的数据放到了_data中(_data里的数据做了数据劫持)
Vue中的数据代理.html:
<!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 type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--
1.vue中的数据代理:
通过vm对象来代理data对象中属性的操作(读/写)
2.Vue中数据代理的好处:
更加方便的操作data中的数据3.基本原理:
通过object.defineProperty()把data对象中所有属性添加到vm上.为每一个添加到vm上的属性,都指定一个getter/setter。
在getter/setter内部去操作(读/写)data中对应的属性。
-->
<div id="app">
<h2>姓名:{{name}}</h2>
<!-- vue对象的属性可直接在插值表达式中 -->
<h2>姓名:{{_data.name}}</h2>
<h2>年龄:{{age}}</h2>
</div>
<script type="text/javascript">
let data={
name:"张三",
age:20
}
const vm = new Vue({
el:"#app",
data
})
</script>
</body>
</html>
live server运行后,f12控制台测试为:
vm.name
'张三'
vm.name="王五"
'王五'
vm.name
'王五'
vm._data.name="张柳"
'张柳'
vm.name
'张柳'
vm._data==data
true
如果vue没有做数据代理,f12控制台只能访问vm._data.name了,加上数据代理,就可以vm.name使用了。
数据代理,就是把_data中的东西放到vm对象身上。
事件处理
事件的基本使用.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>事件的基本使用</title>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--
事件的基本使用:
1.使用v-on : xxx或@xxx绑定事件,其中xxx是事件名;
2.事件的回调需要配置在methods对象中,最终会在vm上;
3.methods中配置的函数,不要用箭头函数!否则this就不是vm了;
4.methods中配置的函数,都是被Vue所管理的函数,this的指向是vm或组件实例对象
5.@click="demo”和L@click="demo($event)”效果一致,但后者可以传参;
-->
<div id="root">
<h2>欢迎来到{{name}}学习</h2>
<button v-on:click="showInfo">点我显示提示信息</button><br/>
<!-- 也可写成@click -->
<button @click="showInfo2">点我显示提示信息2</button><br/>
<!-- 事件传递参数进入 一个参数直接写,如果要用到event,需要$event占位-->
<button @click="showInfo3(66,'你好',$event)">点我显示提示信息3</button>
</div>
<script type="text/javascript">
const vm = new Vue({
el:"#root",
data:{
name:"尚硅谷",
//虽然方法也可写在data中,但会增加vue负担,会也做数据代理和数据劫持
},
methods:{
showInfo(event){
console.log(event.target.innerText)//点我显示提示信息
console.log(this)//此处的this是vue对象
alert("你好")
},
showInfo2:(event)=>{
console.log(this)//此处的this没有自己的this,就找到了全局的Window
},
//所以推荐所有被vue管理的函数要写成普通函数,不用写箭头函数
showInfo3(num,hello,event){
console.log(num)
console.log(hello)
console.log(event)
},
}
})
</script>
</body>
</html>
天气案例.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>天气案例</title>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<div id="root">
<h3>今天天气很{{info}}</h3>
<button @click="changeWeather">切换天气</button><br/>
<!-- 简单的@click事件可如下这样写 -->
<button @click="isHot=!isHot">切换天气</button><br/>
<!-- 甚至vm中data中可以把window也引过来,但不推荐这样写哈 -->
<button @click="window.alert('你好')">切换天气</button>
</div>
</body>
<script type="text/javascript">
new Vue({
el:"#root",
data:{
isHot:true,
window
},
computed:{
info(){
return this.isHot? "炎热":"寒冷"
}
},
methods: {
changeWeather(){
this.isHot = !this.isHot
}
},
})
</script>
</html>
事件修饰符
阻止默认行为、阻止冒泡、事件只触发一次. . .
demo.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>事件修饰符</title>
<script type="text/javascript" src="../js/vue.js"></script>
<style>
*{
margin-top: 20px;
}
.demo1{
height: 50px;
background: blanchedalmond;
}
.box1{
background-color: aqua;
padding: 10px;
}
.box2{
padding: 10px;
background-color: rgb(213, 221, 123);
}
.list{
width: 200px;
height: 200px;
background-color:coral;
/* 形成滚动条 */
overflow: auto;
}
li{
height: 100px;
}
</style>
</head>
<body>
<!-- Vue中的事件修饰符:
1.prevent: 阻止默认事得(常用);
2.stop:阻止事件冒泡(常用);
3.once:事件只触发一次(常用);
4.capture:使用事件的捕获模式;
5.self:只有event.target是当前操作的元素是才触发事件;
6.passive:事件的默认行为立即执行,无需等待事件回调执行完毕; -->
<div id="root">
<h2>欢迎来到{{name}}学习</h2>
<a href="http://www.baidu.com" @click="showInfo">百度</a><br/>
<!-- 阻止了事件的默认行为方式2 .prevent就是事件修饰符-->
<a href="http://www.baidu.com" @click.prevent="showInfo2">百度2</a>
<!-- 阻止事件冒泡 @click.stop -->
<div class="demo1" @click="showInfo2">
<button @click.stop="showInfo2">点我提示信息</button>
</div>
<!-- 事件只触发一次 -->
<button @click.once="showInfo2">点我提示信息</button>
<!-- 使用事件的捕获模式 -->
<div class="box1" @click="showMsg(1)">
div1
<div class="box2" @click="showMsg(2)">
div2
</div>
</div>
<!-- 当上面div2点击后,控制台先打印2,再打印1,如果给外面盒子div1加上捕获capture,就会先捕获在处理了,就先打印1,再打印2了 -->
<div class="box1" @click.capture="showMsg(1)">
div1
<div class="box2" @click="showMsg(2)">
div2
</div>
</div>
<!-- 只有event.target是当前操作的元素是才触发事件; -->
<div class="demo1" @click.self="showInfo3">
<button @click="showInfo3">点我提示信息</button>
<!--外层div事件修饰符不加self:f12控制台打印了两边按钮的元素,说明还是这个按钮的事件,所以给外层div加上一个事件修饰符self也从某种意义上阻止了事件冒泡
<button>点我提示信息</button>
<button>点我提示信息</button>
-->
</div>
<!-- passive:事件的默认行为立即执行,无需等待事件回调执行完毕; -->
<ul @wheel.passive="demo" class="list">
<!--@scroll滚轮和拖曳滚动条均可 @whell是仅滚轮滚动 -->
<!-- 绑定的demo函数中有个很繁琐的for循环,默认会等demo函数完全执行完之后才会执行滚轮的默认事件,加上passive,就会不用等demo函数执行完就执行滚轮的默认事件向下滚动了。passive进行优化的,如移动端手机或平板肯恶搞会使用一下。 -->
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
</div>
<script type="text/javascript">
const vm = new Vue({
el:"#root",
data:{
name:"尚硅谷"
},
methods:{
showInfo(event){
event.preventDefault()//阻止了事件的默认行为方式1
alert("你好")
},
showInfo2(event){
//event.stopPropagation();
alert("你好")
},
showMsg(msg){
console.log(msg)
},
showInfo3(event){
console.log(event.target)
},
demo(){
for(let i=0;i<100000;i++){
console.log("#")
}
console.log("累坏了")
}
}
})
</script>
</body>
</html>
事件修饰符,也可以连着写,@click.stop.prevent=showInfo()
键盘事件
键盘事件.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>键盘事件</title>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--
1.Vue中常用的按键别名:
回车 => enter 删除=> delete(捕获"删除”和“退格”键) 退出=>esc
空格=> space换行=> tab 上 => up 下=> down 左=>left 右=> right
2.Vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转为kebab-case(短横线命名)
3.系统修饰键(用法特殊):ctrl、alt、 shift、meta即win键
(1).配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。
(2).配合keydown使用:正常触发事件。
4.也可以使用keyCode去指定具体的按键(不推荐)
5.Vue.config. keyCodes.自定义键名=键码,可以去定制按键别名
-->
<div id="root">
<input type="text" placeholder="按下回车键提示输入" @keyup="showInfo"/><br/>
<!-- vue给常用的按键起了别名 Enter别名enter -->
<input type="text" placeholder="按下回车键提示输入" @keyup.enter="showInfo2"/><br/>
<!-- Vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转为kebab-case(短横线命名) -->
<input type="text" placeholder="按下caps-lock键提示输入" @keyup.caps-lock="showInfo2"/><br/>
<!-- 对于tab,必须使用keydown,不能使用keyup -->
<input type="text" placeholder="按下tab键提示输入" @keydwon.tab="showInfo2"/><br/>
<!--
3.系统修饰键(用法特殊):ctrl、alt、 shift、meta即win键
(1).配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。
(2).配合keydown使用:正常触发事件。
-->
<input type="text" placeholder="按下shift键提示输入" @keydown.shift="showInfo2"/><br/>
<!-- 4.也可以使用keyCode去指定具体的按键(不推荐)可读性差 -->
<input type="text" placeholder="按下回车键提示输入" @keydown.13="showInfo2"/><br/>
<!-- Vue.config. keyCodes.自定义键名=键码,可以去定制按键别名 -->
<input type="text" placeholder="按下回车键提示输入" @keydown.huiche="showInfo2"/><br/>
<!-- 查看键盘按键的key和keyCode -->
<input type="text" placeholder="按下键提示输入" @keyup="showInfo3"/><br/>
</div>
<script type="text/javascript">
//5.Vue.config. keyCodes.自定义键名=键码,可以去定制按键别名
Vue.config.keyCodes.huiche = 13
const vm =new Vue({
el:"#root",
data:{
name:"张三"
},
methods:{
showInfo(e){
if(e.keyCode!=13) return
console.log(e.keyCode)
console.log(e.target.value)
},
showInfo2(e){
console.log(e.target.value)
},
showInfo3(e){
console.log(e.key,e.keyCode)
/*
Control 17
Shift 16
CapsLock 20
*/
}
}
})
</script>
</body>
</html>
如果需要按下shift+y时触发事件:@keydown.shift.y="showInfo2" 连写
不用计算属性,使用{{方法()}}
计算属性
计算属性.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>姓名案例-插值语法实现</title>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--
计算属性:
1.定义:要用的属性不存在,要通过已有属性计算得来,不能是脱离vue的变量。
2.原理:底层借助了objcet.defineproperty方法提供的getter和setter。
3.get函数什么时候执行?
(1).初次读取时会执行一次。
(2).当依赖的数据发生改变时会被再次调用。
4.优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。
5.备注:
1.计算属性最终会出现在vm上,直接读取使用即可。
2.如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生
-->
<div id="root">
姓:<input type="text" v-model="firstName"><br/><br/>
名:<input type="text" v-model="lastName"><br/><br/>
<!-- {{计算属性无括号}} -->
全名:<span>{{ fullName }}</span><br/>
全名:<span>{{ fullName }}</span><br/>
全名:<span>{{ fullName }}</span><br/>
全名:<span>{{ fullName2 }}</span><br/>
全名:<span>{{ fullName3 }}</span><br/>
<!-- 即使引用了多个fullName,实际上fullName的get方法也只是被执行了一次,然后缓存了 -->
</div>
<script type="text/javascript">
const vm = new Vue({
el:"#root",
data:{
firstName:"张",
lastName:"三"
},
computed:{ //vm区找fullName的get方法,拿到返回值赋值给fullName
fullName:{
/*
l、get有什么作用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
2、get什么时候调用?1.初次读取fullName时。2.所依赖的数据发生变化时。
*/
get(){
return this.firstName+"-"+this.lastName
},
//set不是必须写的,当fullName被修改时调用
set(value){
const arr = value.split('-')
this.firstName = arr[0]
this.lastName = arr[1]
}
//f12中vm.fullname= "李-四"
},
//计算属性简写
fullName2:function(){
return this.firstName+"-"+this.lastName
},
//计算属性简写
fullName3(){
return this.firstName+"-"+this.lastName
}
}
})
</script>
</body>
</html>
监视属性
监视属性也叫侦听属性。
天气案例-监视属性.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>天气案例</title>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--
监视属性watch:
1.当被监视的属性变化时,回调函数自动调用,进行相关操作
2.监视的属性必须存在,才能进行监视!!
3.监视的两种写法:
( 1).new Vue时传入watch配置(2).通过vm.$watch监视
-->
<div id="root">
<h3>今天天气很{{info}}</h3>
<button @click="changeWeather">切换天气</button><br/>
</div>
</body>
<script type="text/javascript">
const vm = new Vue({
el:"#root",
data:{
isHot:true,
},
computed:{
info(){
return this.isHot? "炎热":"寒冷"
}
},
methods: {
changeWeather(){
this.isHot = !this.isHot
}
},
watch:{
isHot:{
/*handler(){
console.log('isHot被修改了')
}*/
// handler什么时候调用?当isHot发生改变时。
handler(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
},
immediate:true //初始化时让handler调用一下,默认false f12刷新王爷后立即 isHot被修改了 true undefined
},
//简写方式 当只有handler时可以开始简写形式
/*isHot(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
},*/
}
})
// 监视属性也可这样写
/*vm.$watch('isHot',{
// handler什么时候调用?当isHot发生改变时。
handler(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
},
immediate:true
})*/
//监视属性$watch的简写 仅有handler时可简写
/*vm.$watch('isHot',function(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)})*/
</script>
</html>
深度监视
深度监视.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>天气案例</title>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--
深度监视:
(1).vue中的watch默认不监测对象内部值的改变(一层)。
(2).配置deep:true可以监测对象内部值改变(多层)。
备注:
(1).Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以!
(2).使用watch时根据数据的具体结构,决定是否采用深度监视。
-->
<div id="root">
<h3>今天天气很{{info}}</h3>
<button @click="changeWeather">切换天气</button><br/>
<hr/>
<h3>a的数据是{{numbers.a}}</h3>
<button @click="numbers.a++">点我让a加1</button><br/>
<hr/>
<h3>b的数据是{{numbers.b}}</h3>
<button @click="numbers.b++">点我让a加1</button><br/>
</div>
</body>
<script type="text/javascript">
const vm = new Vue({
el:"#root",
data:{
isHot:true,
numbers:{
a:1,
b:1
}
},
computed:{
info(){
return this.isHot? "炎热":"寒冷"
}
},
methods: {
changeWeather(){
this.isHot = !this.isHot
}
},
watch:{
isHot:{
handler(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
}
},
'numbers.a':{//监视多级结构中某个属性的变化,只监视a不监视b
handler(){
console.log("a改变了")
}
},
//再提要求,监视numbers中b属性的变化,c属性的变化,d、e、f...一百多个属性的变化,总不能一个个的写吧
numbers:{
deep:true,//监视多级结构中所有属性的变化
handler(){
console.log("numbers改变了")
}
}
}
})
</script>
</html>
watch对比computed
watch对比computed.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>计算属性和watch</title>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--
computed和watch之间的区别:
1.computed能完成的功能,watch都可以完成。
2.watch能完成的功能,computed不一定能完成,例如: watch可以进行异步操作。
两个重要的小原则;
1.所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm或组件实例对象。
2.所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等),最好写成箭头函数,这样thi的指向才是vm或组件实例对象。
-->
<div id="root">
姓:<input type="text" v-model="firstName"><br/><br/>
名:<input type="text" v-model="lastName"><br/><br/>
全名:<span>{{ fullName }}</span><br/>
</div>
<script type="text/javascript">
const vm = new Vue({
el:"#root",
data:{
firstName:"张",
lastName:"三",
fullName:"张-三"
},
computed:{
/*fullName(){
return this.firstName+"-"+this.lastName
}*/
},
watch:{
firstName(newValue){//相比计算属性赋值,watch中方法还可以使用函数,如计时器。而计算属性中由于依赖返回值,不能开启异步任务维护数据,不能使用计时器
setTimeout(() => {//因为定时器的回调不受vue控制,js引擎调的,所以可以且必须写成箭头函数
//因为不受vue管理,this就往外找,找到了firstName中的this,时vue管理的,所以下面的this.fullName又受vue管理了。倘若不写箭头函数而写普通函数,那this由于不受vue管理,而受window管理,就变成了window.fullName了
this.fullName=newValue+"-"+this.lastName
}, 1000);
},
lastName(val){
this.fullName=this.firstName+"-"+val
}
}
})
</script>
</body>
</html>
绑定class样式
f12元素中可直接编辑,失去焦点就会运用
绑定样式.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>绑定样式</title>
<script type="text/javascript" src="../js/vue.js"></script>
<style>
.basic{
width: 200px;
height: 200px;
border-style: solid;
border-color: blue;
}
.happy{
background-color: rgb(233, 236, 30)
}
.sad{
background-color: rgb(30, 236, 191)
}
.normal{
background-color: rgb(128, 211, 19)
}
.style1{
background-color: rgb(211, 153, 19)
}
.style2{
font-size: 50px;
}
.style3{
border-radius: 20%;
}
</style>
</head>
<body>
<!--
绑定样式:
1.class样式
写法:class="xxx"xxx可以是字符串、对象、数组。
字符串写法适用于:类名不确定,要动态获取。
对象写法适用于:要绑定多个样式,个数不确定,名字也不确定。
数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用.
2. style样式
:style="{fontsize: xxx}"其中xxx是动态值。: style="[a,b]"其中a、b是样式对象。
-->
<div id="root">
<!-- <div class="basic normal" id="demo" @click="changeMod">{{name}}</div> -->
<!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 -->
<div class="basic" :class="mod" @click="changeMod">{{name}}</div><br/><br/>
<!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定、名字也不确定 -->
<div class="basic" :class="arr" >{{name}}</div><br/><br/>
<!-- 绑定class样式--对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用 -->
<div class="basic" :class="classObj" >{{name}}</div><br/><br/>
<!-- css的烤肉串变成驼峰命名 -->
<div class="basic" :style="{fontSize: fsize+'px'}" >{{name}}</div><br/><br/>
<!-- 绑定style样式--对象写法 -->
<div class="basic" :style="styleObj" >{{name}}</div><br/><br/>
<!-- 绑定style样式--数组写法 -->
<div class="basic" :style="[styleObj,styleObj2]" >{{name}}</div><br/><br/>
<div class="basic" :style="styleArr" >{{name}}</div><br/><br/>
</div>
<script type="text/javascript">
const vm = new Vue({
el:"#root",
data:{
name:"张三",
mod:"normal",
arr:["style1","style2","style3"],
/*
可在f12控制台中:
vm.arr.shift()
'style1'
vm.arr.shift()
'style2'
vm.arr.shift()
'style3'
vm.arr.push("style1")
1
vm.arr.push("style2")
2
vm.arr.push("style3")
*/
classObj:{
style1:false,
style2:false
},
fsize:30,
styleObj:{
fontSize: '30px' //css的烤肉串变成驼峰命名
},
styleObj2:{
backgroundColor: "orange" //css的烤肉串变成驼峰命名
},
styleArr:[
{
fontSize: '30px' //css的烤肉串变成驼峰命名
},
{
backgroundColor: "orange" //css的烤肉串变成驼峰命名
}
]
},
methods: {
changeMod(){
//document.getElementById("demo").className='basic happy'//传统的js切换class
//this.mod="happy"
const arr=["happy","sad","normal"]
const index = Math.floor(Math.random()*3) //0-1,乘以3,向下取整
this.mod=arr[index]
}
},
})
</script>
</body>
</html>
条件渲染
条件渲染.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>条件渲染</title>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--
条件渲染:
1.v-if
写法:
(1).v-if="表达式"
(2).v-else-if="表达式"(3).v-else="表达式"适用于:切换频率较低的场景。
特点:不展示的DOM元素直接被移除。
注意:v-if可以和:v-else-if、v-else一起使用,但要求结构不能被"“打断”。
2.v-show
写法:v-show="表达式"
适用于:切换频率较高的场景。
特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉
3.备注:使用v-if的时,元素可能无法获取到,而使用v-show一定可以获取到。
-->
<div id="root">
<!-- 使用v-show做条件渲染,如果为false,就为display:none掉 切换频率高推荐使用v-show-->
<h2 v-show="a">欢迎你:{{name}} </h2>
<h2 v-show="1==1">欢迎你:{{name}} </h2>
<!-- 使用v-if做条件渲染,如果为false,v-if标记的整个组件都不存在了 切换频率低的推荐使用v-if-->
<h2 v-if="a">欢迎你:{{name}} </h2>
<h2 v-if="1==1">欢迎你:{{name}} </h2>
<h2>当前的n值为:{{n}}</h2>
<button @click="n++">点我n+1</button>
<div v-show="n==1">Angular</div>
<div v-show="n==2">React</div>
<div v-show="n==3">Vue</div>
<!-- if成立的话,else-if就不执行了,效率更高一些 -->
<div v-if="n==1">Angular</div>
<div v-else-if="n==2">React</div>
<div v-else-if="n==3">Vue</div>
<div v-else="n==4">哈哈</div>
<!-- v-else不需要写条件,如果写条件了也不生效 -->
<!-- v-if、v-else-if、v-else,v-if为最开始的,且结构体不可被打断,打断后面的代码不生效了 -->
<!-- <template>只能配合v-if,不影响结构 -->
<template v-if="n==1">
<h2>你好</h2>
<h2>happy</h2>
<h2>hello</h2>
</template>
</div>
<script type="text/javascript">
new Vue({
el:"#root",
data:{
name:"张三",
a:false,
n:0
}
})
</script>
</body>
</html>