1.监视属性
先推荐大家安装第一个vscode常用插件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>天气案例_监视简写</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器 -->
<div id="root">
<h2>今天天气很{{weather}}</h2>
<button @click="change">切换天气</button>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示
const vm = new Vue({
el: "#root",
data: {
isHot: true,
},
methods: {
change() {
this.isHot = !this.isHot;
}
},
computed: {
weather() {
return this.isHot ? "炎热" : "寒冷"
}
},
watch: {
//当只有handler的时候才能使用简写形式
// isHot: {
// handler(newValue, oldValue) {
// console.log("isHot被修改了", newValue, oldValue);
// }
// // deep:true,
// // immediate: true//初始化时让handler调用一下
// }
//简写形式
// isHot(newValue, oldValue) {
// console.log("isHot被修改了", newValue, oldValue);
// }
}
})
//完整写法
// vm.$watch('isHot', {
// handler(newValue, oldValue) {
// console.log("isHot被修改了", newValue, oldValue);
// }
// })
//简写
vm.$watch('isHot', function (newValue, oldValue) {
console.log("isHot被修改了", newValue, oldValue);
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>姓名案例_watch实现</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
<style>
* {
padding: 5px;
margin: 5px;
}
</style>
</head>
<!--
computed和watch之间的区别:
1.computed能完成的功能,watch都可以完成。
2.watch能完成的功能,computed不一定能完成,
例如:watch可以进行异步操作。
两个重要的小原则:
1.所被vue管理的函数,最好写成普通函数,这样this的指向才是vm 或组件实例对象。
2.所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数、promise的回调函数 等),最好写成箭头函数,这样this的指向才是vm 或组件实例对象。
-->
<body>
<!-- 准备好一个容器 -->
<div id="root">
<!-- 以后注意在模板中 {{}} 中到底写的是 data中属性 还是 methods中的方法 还是 computed里的计算属性 嗯! -->
<div id="father" style="width: 300px;border: 2px red solid;margin:auto auto;">
<span>姓:</span> <input type="text" style=" width: 100px; height: 15px;" v-model="name.lastName"><br>
<span>名:</span> <input type="text" style=" width: 100px; height: 15px;" v-model="name.firstName"><br>
<span>全名:</span>
<div style="display: inline-block;width: 150px;height: 15px;margin-left: 40px;">
<span>{{fullName}}</span><br>
</div><br>
</div>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示
const vm = new Vue({
el: "#root",
data: {
name: {
lastName: '',
firstName: ''
},
fullName: ''
},
watch: {
name: {
deep: true,
handler(n, o) {
// vue管理函数 箭头函数 this==window 普通函数 vue代理 所以 this==vm
// 而普通函数 在vue管理函数里执行 箭头函数用的就是 this外面的对象 所以this == vm,若是用普通函数 ,因为这个函数用了普通函数this
// 传进来了。那么this 就是window调用的 this==window
//如果写成普通函数 那么this 就是windows
setTimeout(function(){
//异步任务延迟 用 watch
this.fullName = this.name.lastName + '-' + this.name.firstName;
}, 1000);//ms
setTimeout(() => {
//异步任务延迟 用 watch
this.fullName = this.name.lastName + '-' + this.name.firstName;
}, 1000);//ms
}
}
}
})
</script>
</body>
</html>
2.绑定样式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>绑定样式</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
<style>
/* 基础 */
.basic {
width: 400px;
height: 100px;
padding: 30px;
border: 1px solid black;
}
/* 三选一 */
.happy {
background-color: red;
}
.sad {
background-color: grey;
}
.normal {
background-color: skyblue;
}
.j_aW{
background-color: pink;
}
/* 三个能同时使用 */
.atjmj1 {
background-color: greenyellow;
}
.atjmj2 {
font-size: 60sp;
}
.atjmj3 {
border-radius: 30px;
}
</style>
</head>
<!--
绑定样式:
1.class样式
写法 :class="xxx" xxx可以是字符串、对象、数组。
字符串写法适用于:类名不确定,要动态获取。
对象写法适用于:要绑定多个样式,个数不确定,名字也不确定。
数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用。
2.style样式
:style="{fontSize:xxx}" 其中xxx是动态值。
:style="[a,b]" 其中a、b是样式对象。
-->
<body>
<!-- 准备好一个容器 -->
<div id="root">
<!-- 会把class 和 :class里面都汇总成最终一个 class了 -->
<!-- 绑定class样式 --字符串写法 适用于:样式的类名不确定,需要动态确定 -->
<div class="basic" :class="mood" id="demo" @click="changeMood">test</div>
<hr>
<!-- 绑定class样式 --数组写法 适用于:样式的个数不确定,名字也不确定-->
<div class="basic" :class="classArr">test</div>
<button @click="removeArrFirst">移掉数组第一个元素</button><br>
请输入样式名 <input type="text" v-model="styleName"> <button @click="submit">点击提交</button>
<hr>
<!-- 绑定class样式 --对象写法,适用于:要绑定的样式个数确定 名字也确定,但要动态决定用不用 -->
<div class="basic" :class="classObj">test</div>
<hr>
<h1>内联样式</h1>
<!-- <div class="basic" :style="{fontSize: fsize+'px'}">test</div> -->
<div class="basic" :style="styleObj">test</div>
<!-- 绑定style 样式 --对象写法 -->
<hr>
<!-- 绑定style 样式 --数组写法 -->
<div class="basic" :style="[styleObj,styleObj2]">test</div>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示
const vm = new Vue({
el: "#root",
data: {
mood: 'happy',
classArr: ['atjmj1', 'atjmj2', 'atjmj3'],
styleName: '',
classObj:{
atjmj1:false,
atjmj3:false,
j_aW:true
},
fsize:40,
styleObj:{
fontSize: '40px',
color:'red'
},
styleObj2:{
backgroundColor:'orange'
}
},
methods: {
changeMood(event) {
const classArr = ['happy', 'sad', 'normal']
// document.getElementById('demo').className = 'basic sad';//这样也可以更改样式
// event.target.className = 'basic sad';这样也行
//[0,1)随机值
let index = Math.floor(Math.random() * 3)//向下取整 [0,2]的整数
this.mood = classArr[index]
},
removeArrFirst() {
this.classArr.shift();
},
submit() {
this.classArr.push(this.styleName);
}
},
})
</script>
</body>
</html>
3.条件渲染
1.v-show
v-show的底层实现就是 display:none ,不删除dom节点
2.v-if
直接把dom都干掉
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>条件渲染</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<!--
条件渲染:
1.v-if
写法:
(1).v-if="表达式"
(2).v-else-if="表达式"
(3).v-else="表达式"
适用于:切换频率较低的场景。
特点:不展示的DOM元素直接被移除。
注意:v-if可以和:vrelse-if、v-else一起使用,但要求结构不能被“打断”。
2.v-show
写法:v-show="表达式"
适用于:切换频率较高的场景。
特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉
3.备注:使用v-if的时,元素可能无法获取到,而使用v-show一定可以获取到。
-->
<body>
<!-- 准备好一个容器 -->
<div id="root">
<!-- 使用v-show做条件渲染 -->
<!-- <h2 v-show="isShow">欢迎来到{{name}}</h2> -->
<!-- <h2 v-show="1===1">欢迎来到{{name}}</h2> -->
<!-- 使用v-if做条件渲染 -->
<!-- <h2 v-if="isShow">欢迎来到{{name}}</h2> -->
<h2>当前的n值是{{n}}</h2>
<button @click="n++">点我n+1</button>
<div v-show="true">
<ol>
<li v-show="n===1">Angular</li>
<li v-show="n===2">React</li>
<li v-show="n===3">Vue</li>
</ol>
<ol>
<li v-if="n===1">Angular</li>
<li v-if="n===2">React</li>
<li v-if="n===3">Vue</li>
</ol>
<!-- v-if v-else 和 v-else-if -->
<ul>
<li v-if="n===1">Angular</li>
<li v-else-if="n===2">React</li>
<li v-else>Vue</li>
</ul>
</div>
<!-- template不影响结构 就不用加div了 只能配合v-if -->
<template v-if="n===1">
<h2>你好</h2>
<h2>尚硅谷</h2>
<h2>北京</h2>
</template>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示
const vm = new Vue({
el: "#root",
data: {
name: 'jmj',
isShow: false,
n: 0
}
})
</script>
</body>
</html>
4.列表渲染
1.基本列表
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>基本列表</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器 -->
<div id="root">
<!-- 遍历数组 -->
<h2>人员列表 遍历数组(用得最多)</h2>
<ul>
<!-- :key 让每一个li都有一个唯一的标识 -->
<!-- <li v-for="person in persons" :key="person.id">
{{person.name}} - {{person.age}}
</li> -->
<!-- <li v-for="(person,index) in persons" :key="person.id">
{{index}} - {{person.name}} - {{person.age}}
</li> -->
<!-- 把key设置为索引 -->
<!-- <li v-for="(person,index) in persons" :key="index">
{{index}} - {{person.name}} - {{person.age}}
</li> -->
<!-- of和in都行 -->
<li v-for="(person,index) of persons" :key="person.id">
{{index}} - {{person.name}} - {{person.age}}
</li>
<!-- 遍历对象 -->
<h2>人员列表 遍历对象 </h2>
<li v-for="(value,key) of car" :key="key">
{{key}}={{value}}
</li>
<h2>人员列表 遍历字符串(用得少) </h2>
<li v-for="(value,key) of str" :key="key">
{{key}}={{value}}
</li>
<h2>人员列表 遍历指定次数(用得少) </h2>
<li v-for="(num,index) of 5" ::key="index">
{{index}}={{num}}
</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示
const vm = new Vue({
el: "#root",
data: {
persons: [
{
id: '001',
name: '张三',
age: 18
},
{
id: '002',
name: '李四',
age: 19
},
{
id: '003',
name: '王五',
age: 20
}
],
car: {
name: '奥迪A8',
price: '70万',
color :'黑色'
},
str:'hello'
}
})
</script>
</body>
</html>
2.key原理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>key原理</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<!--
面试题:react、vue中的key有什么作用?(key的内部原理)
1.虚拟DOM中key的作用:
key是虚拟DoM对象的标识,当状态中的数据发生变化时,Vue会根据【新数据】生成【新的虚拟DoM】,
随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:
2.对比规则:
(1).旧虚拟DOM中找到了与新虚拟DOM相同的key:@.若虚拟DOM中内容没变,直接使用之前的真实DOM!@.若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM。
(2).旧虚拟DOM中未找到与新虚拟DOM相同的key创建新的真实DOM,随后渲染到到页面。
3.用index作为key可能会引发的问题:
1.若对数据进行:逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新==>界面效果没问题,但效率低。
2.如果结构中还包含输入类的DOM:会产生错误DOM更新==>界面有问题。
4.开发中如何选择key?:
1.最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号、学号等唯一值。
2.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,
使用index作为key是没有问题的。
-->
<body>
<!-- 准备好一个容器 -->
<div id="root">
<!-- 遍历数组 -->
<div><button @click="add">添加一个老刘</button></div>
<h2>人员列表 遍历数组(用得最多)</h2>
<ul>
<li v-for="(person,index) of persons" :key="index">
{{index}} - {{person.name}} - {{person.age}}
<input type="text" :class="person.class" v-model:value="person.value">
</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示
const vm = new Vue({
el: "#root",
data: {
persons: [
{
id: '001',
name: '张三',
age: 18,
class: "x",
value: '张三'
},
{
id: '002',
name: '李四',
age: 19,
class: "x",
value: '李四'
},
{
id: '003',
name: '王五',
age: 20,
class: "x",
value: '王五'
}
]
},
methods: {
add() {
//虚拟dom好像不会对比样式 只要是同一个标签 值一样,就不会被替换
const p = { id: '004', name: '老刘', age: 40, class: 'y', value: '老刘' };
// this.persons[0].class='t';
//往数组前方加东西
this.persons.unshift(p);
// this.persons.shift();//从前面删除
}
},
})
</script>
</body>
</html>
3.列表过滤
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>列表过滤</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器 -->
<div id="root">
<!-- 遍历数组 -->
<h2>人员列表</h2>
<input type="text" placeholder="请输入名字" v-model="searchObj.keywords">
<ul>
<!-- <li v-for="(person,index) of persons" :key="person.id" v-show="person.name.includes(search)">
{{index}} - {{person.name}} - {{person.age}} - {{person.sex}}
</li> -->
<li v-for="(person,index) of filterArr" :key="person.id">
{{index}} - {{person.name}} - {{person.age}} - {{person.sex}}
</li>
</ul>
</div>
<!-- 推荐用计算属性实现 -->
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示
const vm = new Vue({
el: "#root",
data: {
search: '',
searchObj: {
keywords: ''
},
persons: [
{
id: '001',
name: '马冬梅',
sex: '女',
age: 23
},
{
id: '002',
name: '周杰伦',
sex: '男',
age: 19
},
{
id: '003',
name: '温兆伦',
sex: '男',
age: 18
},
{
id: '004',
name: '周冬雨',
sex: '女',
age: 20
}
]
},
computed: {
filterArr() {
//includes可以包含空字符串 indexOf包含空字符下标是0
return this.persons.filter(p => p.name.includes(this.searchObj.keywords));
}
},
})
</script>
</body>
</html>
4.列表排序
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>列表排序</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器 -->
<div id="root">
<!-- 遍历数组 -->
<h2>人员列表</h2>
<input type="text" placeholder="请输入名字" v-model="searchObj.keywords">
<button @click="asc">年龄升序</button>
<button @click="desc">年龄降序</button>
<button @click="origin">原顺序</button>
<ul>
<!-- <li v-for="(person,index) of persons" :key="person.id" v-show="person.name.includes(search)">
{{index}} - {{person.name}} - {{person.age}} - {{person.sex}}
</li> -->
<li v-for="(person,index) of filterArr" :key="person.id">
{{index}} - {{person.name}} - {{person.age}} - {{person.sex}}
</li>
</ul>
</div>
<!-- 推荐用计算属性实现 -->
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示
const vm = new Vue({
el: "#root",
data: {
search: '',
searchObj: {
keywords: ''
},
soft:{
asc:false,
desc:false
},
persons: [
{
id: '001',
name: '马冬梅',
sex: '女',
age: 23
},
{
id: '002',
name: '周杰伦',
sex: '男',
age: 19
},
{
id: '003',
name: '温兆伦',
sex: '男',
age: 18
},
{
id: '004',
name: '周冬雨',
sex: '女',
age: 20
}
]
},
computed: {
filterArr() {
//js里 0也可以是 false !0就是true
//includes可以包含空字符串 indexOf包含空字符下标是0
return this.persons.filter(p => p.name.includes(this.searchObj.keywords)).sort((a,b)=>{
if(this.soft.asc){
return a.age - b.age;
}else if(this.soft.desc){
return b.age - a.age;
}else{
return 0;
}
});
}
},
methods: {
asc(){
this.soft.asc =true;
this.soft.desc =false;
},
desc(){
this.soft.asc =false;
this.soft.desc =true;
},
origin(){
this.soft.asc =false;
this.soft.desc =false;
}
},
})
</script>
</body>
</html>
5.模拟数据检测
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<script type="text/javascript">
let data = {
name: '辽工',
address: '北京',
student:{
name:'tom',
age:18
}
}
let vm={
}
//构造函数
//创建一个监视的实例对象,用于监视data中属性的变化
const obj = new Observer(data);
vm._data =data = obj
console.log(vm);
console.log(vm._data === data);
//创建一个监视的实例对象
function Observer(obj) {
//汇总对象中所有的属性形成一个数组
const keys = Object.keys(obj);
// console.log(keys);
//遍历
keys.forEach((k) => {
//this是实例对象
Object.defineProperty(this, k, {
get() {
console.log(k+'被读取了');
return obj[k];
},
set(val) {
console.log(k+'被改变了,我要去解析模板,生成虚拟dom.. 我要开始忙了,改变的值为:'+val);
obj[k] = val;
}
})
})
}
//定时器
// setInterval(()=>{
// if(data.name!=='辽工'){
// console.log('name被改变');
// }
// },1000)
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<!--
数据劫持 数据代理 都离不开 Object.defindedProperty(target,key,{
get(){
},
set(){
}
}) 这个方法
Vue数据劫持:意思就算数据加工,把传入的对象里的每一个属性都遍历一遍,都给他进行加工,这个动作就叫做数据劫持
Vue监视数据的原理:
1.vue会监视data中所有层次的数据。
2.如何监测对象中的数据?
通过setter实现监视,且要在new Vue时就传入要监测的数据。
(1).对象中后追加的属性,Vue默认不做响应式处理
(2).如需给后添加的属性做响应式,请使用如下API:
Vue.set(target,propertyName/index,value) 或
vm.$set(target, propertyName/index, value)
3.如何监测数组中的数据?
通过包裹数组更新元素的方法实现,本质就是做了两件事:
(1).调用原生对应的方法对数组进行更新。
(2).重新解析模板,进而更新页面。
4.在Vue修改数组中的某个元素一定要用如下方法:
1.使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse() //这些添加的对象也都是递归变成响应式的对象添加进去
2.Vue.set()或 vm.$set()
特别注意:Vue.set()和 vm.$set()不能给vm或vm的根数据对象添加属性!!!
通过代理的set添加的对象,以及其子对象都是响应式的,
而数组比较特殊,对每一项不会做响应式,但是里面的对象以及子对象的属性都是响应式的,要想修改数组,就调用上面API,vue实现的动态代理,都可以帮你实现响应式
-->
<body>
<!-- 准备好一个容器 -->
<div id="root">
<h1>学生信息</h1>
<button @click="student.age++">年龄添加一岁</button>
<button @click="fun1">添加性别属性,默认值:男</button>
<button @click="fun2">在列表首位添加一个朋友</button>
<button @click="fun3">修改第一个朋友的名字为:张三</button>
<button @click="fun4">添加一个爱好</button>
<button @click="fun5">修改第一个爱好为:开车</button>
<button @click="fun6">过滤掉爱好:抽烟</button>
<h3>姓名:{{student.name}}</h3>
<h3>年龄:{{student.age}}</h3>
<h3 v-if="student.sex">性别:{{student.sex}}</h3>
<h3>爱好:</h3>
<ul>
<li v-for="(h,index) in student.hobby" :key="index">
{{h}}
</li>
</ul>
<h3>朋友们:</h3>
<ul>
<li v-for="(f,index) in student.friends" :key="index">
{{f.name}}--{{f.age}}
</li>
</ul>
</div>
<script type="text/javascript" >
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示
const vm = new Vue({
el:"#root",
data: {
student:{
name:'tom',
age:18,
hobby:['抽烟','喝酒','烫头'],
friends:[
{name:'jerry',age:35},
{name:'tony',age:36}
]
}
},
methods: {
fun1(){
Vue.set(this.student,'sex','男');
},
fun2(){
let friend = {name:'jack',age:37}
console.log(friend);
this.student.friends.unshift(friend);
},
fun3(){
this.student.friends[0].name = '张三';
},
fun4(){
this.student.hobby.push('乒乓球');
},
fun5(){
// this.student.hobby.splice(0,1,'开车');
// Vue.set(this.student.hobby,0,'开车')
this.$set(this.student.hobby,0,'开车')
},
fun6(){
this.student.hobby = this.student.hobby.filter((h)=>h!=='抽烟')//就算赋给普通集合,也会通过vm所劫持的set方法把普通集合里的所有对象都变成响应式的,
}
},
})
</script>
</body>
</html>