7、样式的一些写法
<!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>
<style>
.basic {
height: 100px;
width: 100px;
}
.selfColor {
background-color: pink;
}
.selfSize {
font-size: large;
}
.selfWeight {
font-weight: 400;
}
</style>
</head>
<body>
<!-- 1、动态绑定class -->
<!-- 字符串写法,用于样式类名不确定,需要动态绑定 -->
<div class="basic" :class="color">你好</div>
<!-- 要绑定的样式个数和名称都不确定 -->
<div class="basic" :class="classArr">你好</div>
<!-- 名称确定、个数也确定,但是动态决定要不要添加 -->
<div class="basic" :class="classObj">你好</div>
<script>
const color = 'selfColor';
const classArr = ['selfColor', 'selfSize', 'selfWeight'];
const classObj = {
selfColor: true,
selfSize: true,
selfWeight: false
}
// 考虑一下,如果classObj里的样式判定是动态的,那么可以把它写成get()、set()形式
</script>
<!-- 2、动态绑定style -->
<!-- 对象形式绑定,注意对象里是驼峰命名法 -->
<div :style="styleObj">你好</div>
<!-- 数组形式绑定,注意对象里是驼峰命名法 -->
<div :style="styleObjArr">你好</div>
<script>
const num = 5;
const styleObj = {
fontSize: num + 'px',
color: 'red',
backgroundColor: 'pink'
}
const styleObjArr = [
{
fontSize: num + 'px',
color: 'red',
backgroundColor: 'pink'
},
{
fontWeight: 400,
border: '1px solid pink'
}
]
</script>
</body>
</html>
8、v-if的注意点
<body>
<div v-if="true">
<h2>你好</h2>
<h2>你好</h2>
<h2>你好</h2>
</div>
<template v-if="true">
<h2>你好</h2>
<h2>你好</h2>
<h2>你好</h2>
</template>
<script>
// 注意:v-if和v-else以及v-else-if,三者在一起使用时,
// 他们必须紧紧的挨在一起,不能被打断,否则会失效
// 这里还要说一个东西比如有三个h标签,我想他们同时被一个条件控制是否显示
// 这里有两种写法,一种是div包着,一种是template包着,
// 哪个好呢,当然是template了,应为它不会改变html结构,而div破坏了结构
// 你看渲染的结果,template不会被渲染出来,这就是template的好处
// 但是一定要注意,template只能和v-if搭配使用,不能和v-show搭配使用
</script>
</body>
9、v-for中的key
<body>
<div v-for="(num, index) in arr" :key="index">
{{num}}
</div>
<script>
const arr = [2,5,4,8,4];
// 首先这个key不是给真实DOM用的,而是给虚拟DOM用的,是放在虚拟DOM标签里的,真实DOM不会携带key
// 1、虚拟DOM中key的作用:
// key就是虚拟DOM的标识,当状态数据发生变化时,Vue会根据新数据生成新的虚拟DOM
// 随后Vue进行新虚拟DOM与旧虚拟DOM的差异比较,比较规则如下
// 2、对比规则:
// 旧虚拟DOM中找到了与新虚拟DOM相同的key:
// 若虚拟DOM中内容没变,直接使用之前的真实DOM
// 如果虚拟DOM内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
// 旧虚拟DOM中未找到与新虚拟DOM相同的key
// 创建新的真实DOM,随后渲染到页面
// 3、用index作为key可能会引发的问题
// 若对数据进行逆序添加、逆序删除等破坏顺序操作(比如往数组第一位添加元素),会产生没有必要的真实DOM更新,
// 虽然界面没问题,但是效率低
// 如果结构中还包含输入类的DOM,比如li里面包着input,会产生错误DOM更新,此时界面有问题
// 注意:
// 内存里对比的是虚拟DOM,虚拟DOM就是内存中的一堆数据,对比用的是diff算法
// 当对比虚拟DOM时,发现一样的地方,那么新的虚拟DOM就不会再转成真实的DOM
// 而是直接把旧虚拟DOM的转换成的真实DOM直接拿过来用
// 具体看尚硅谷的Vue教程第30集
</script>
</body>
10、Vue的数据监视的原理:数据劫持
<body>
<button @click="updateMessage">更新信息</button>
<div v-for="(p, index) in persons" :key="p.id">
{{p.name}}-{{p.age}}
</div>
<script>
// 先发现一个问题
new Vue({
el: '#root',
data: {
persons: [
{ id: '001', name: 'jjwu27', age: 18 },
{ id: '002', name: 'jjwu26', age: 19 },
{ id: '003', name: 'jjwu28', age: 17 }
]
},
methods: {
updateMessage() {
// this.persons[0].name = 'jjwu29'; //奏效,vue可以监听到并实时更新
// this.persons[0].age = 20; //奏效,vue可以监听到并实时更新
// 下面这个有意思,这个改变vue监听不到,数据虽然改了但是页面不会更新
this.persons[0] = { id: '001', name: 'jjwu29', age: 20 };
}
}
})
</script>
<script>
// 模拟一个vue的数据响应式监听
let data = {
name: '尚硅谷',
address: '北京'
}
// Vue底层写了一个构造函数
// 在构造函数里创建了一个监视的实例对象,用于监视obj中属性的变化
function Observer(obj) {
// 汇总对象中所有的属性形成一个数组
const keys = Object.keys(obj);
keys.forEach(k => {
// 构造函数里的this指向他实例化的对象
Object.defineProperty(this, k, {
get() {
return obj[k];
},
set(val) {
obj[k] = val;
}
})
})
}
const obs = Observer(data);
// 接下来
let vm = {} // 模仿Vue实例对象
vm._data = data = obs;
// 以上就是数据劫持
// 那我们说到的数据代理啊其实就是
// 我们在用数据的时候需要vm._data.name
// 但是在vue里面可以直接vm.name,它把name拿出来了,就是做了一层数据代理
// 当然如果数据是多层级的对象,那么深度监听就用递归实现
</script>
<script>
// Vue.set()的使用,也就是vm.$set(),好好想想为什么他两是一样的,这就是
// 构造函数和实例对象之间的关系
// 直接给对象添加属性,这个属性是没有getter和setter的,Vue是监听不到的
// Vue.set()可以,它添加的属性是有
// 注意:这一块不是为了和你说Vue.set()有多好用的,而是想给你说这玩意的局限性
const vm = new Vue({
el: '#root',
data: {
name: 'jjwu27',
age: 18,
friends: {
name: 'nanguabing',
age: 1
}
}
})
// Vue.set()只能给data里的对象添加属性,不能直接给data添加属性
// 错误写法:
Vue.set(vm.data, 'animal', 'cat');
// 正确写法:
Vue.set(vm.data.friends, 'animal', 'cat');
// 总结:Vue.set()不能动data的根数据
</script>
<script>
// Vue监视数组
const vm = new Vue({
el: '#root',
data: {
name: 'jjwu27',
age: 18,
hobby: ['抽烟', '喝酒', '烫头'],
friends: [
{
name: 'cat'
},
{
name: 'dog'
}
]
}
})
// Vue只会给对象自身以及对象的所有属性添加getter和setter属性,
// 它会给数组本身添加监听属性,但是他不会给数组里的每一项添加呀,这就是关键呀
// 所以直接通过索引去修改数组的值,Vue是监听不到的,也就不是响应式的
// 那Vue是怎么监听数组的呢????
// Vue就想了,那好吧,只有当你改变了原数组,我才监听
// 所以Vue就对会改变原数组的方法做了监听(push、pop、shift、unshift、splice、sort、reverse)
// Vue重新包装了这几个方法,这几个方法和Array.出来的不是同一个东西了,当数组被Vue所管理,那么这个数组的
// 这7个方法就会被Vue做一层封装,当这些方法被调用的时候,Vue会重新生成虚拟DOM做Diff对比,重新解析模版,渲染页面
// 像filter、reduce这种不改变原数组的就不会去监听
// 除此之外,用Vue.set()就可以通过索引改数组值了
Vue.set(vm.hobby, 1, '打台球');
</script>
<script>
// 注意!!!!!!!!!!!!!!!!!!!!!!!
let arr = [
{
name: 'jjwu27'
},
{
name: 'nanguabing'
},
{
name: 'dog'
}
];
// 1、先说一个点,当你通过this.$set()给数组添加一个值,这个值是一个对象
// 那么请问Vue会给这个对象里的所有的属性都添加上getter和setter属性嘛
// 当当当当!!!答案是!!! 会的!!!!!!!!是可以被监听的
// 两种情况:直接操作索引和把索引作为中间站
// Vue监听不到:直接利用索引修改值,因为Vue并没有对数组的索引值做代理
this.arr[0] = { name: 'rong' };
// Vue监听的到的:这种的可以监听到,因为Vue对数组里的索引值里的所有属性做了监听
this.arr[1].name = 'cat';
// 2、再说一个注意:下面这种写法能不能监听到呢
const newArr = [3,5,7];
// 我直接写一个新的数组给他替换掉
arr = newArr;
// 答案是!!!!!!可以监听到!!!!!!!!!!!
// 因为Vue虽然没有对数组里的索引值做监听,但是Vue对这个数组字段做了监听啊!!!!!
const obj = {
name: 'jjwu27',
age: 18
}
// 上面这个对象也是的,Vue会对里面的name和age属性做监听,它当然也会对obj做监听啦,宝贝~~
</script>
</body>
11、自定义指令
<body>
<div id="root">
<span v-text="n"></span>
<span v-big="n"></span>
<button @click="n++">点我加1</button>
<input type="text" v-fbind:value="n">
</div>
<script>
// 需求:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍。
// 需求:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点
new Vue({
el: '#root',
data: {
n: 1
},
// 指令
directives: {
// 方法名称就是指令名称(去掉v-)
big(ele, binding) {
// 这里的ele就是指令(v-big)关联的标签(span)
// 这里的binding就是v-big绑定的信息,其中binding.value就是n
ele.innerText = binding.value * 10;
},
// 这种写法满足不了focus()功能
/* fbind(ele, binding) {
ele.value = binding.value;
ele.focus();
} */
fbind: {
// 指令与元素成功绑定时
bind(ele, binding) {
ele.value = binding.value;
},
// 指令所在元素被插入页面后
inserted(ele, binding) {
ele.focus();
},
// 指令所在的模板被重新解析时
update(ele, binding) {
ele.value = binding.value;
}
}
}
})
// 注意:如何保证v-big绑定的值会实时变化呢
// 也就是说big这个函数要实时调用返回最新的值,那么big函数什么时候会被调用呢???
// 回答!!!!
// 1、指令与元素成功绑定时(初始化)
// 2、指令所在的模板被重新解析时
// 所以可以推断出来:指令写成函数形式就等于对象形式的bind()加update()
// input案例的注意点:
// 1、ele.focus()是否起作用了,我们发现并没有自动聚焦,所以写函数不好使,这时需要把指令写成对象
// 2、为什么focus会失效呢,因为,focus必须在DOM创建完成后写入到body中,这时候调用focus函数才能聚焦
// 而fbind函数的首次调用是指令与元素成功绑定时,这个时候是Vue在解析模板的过程,input标签还没创建
// 放入到body中,所以这个时候调用focus是没有用的
// 还有一个非常重要的地方,指令函数里打印一下this看下
// 他们都是window
</script>
</body>
12、生命周期
<script>
// 注意点:常用的生命周期钩子:
// 1、mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息【一系列初始化工作】
// 2、beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】
// 关于销毁Vue实例:
// 1、销毁后借助Vue开发者工具看不到任何信息
// 2、销毁后自定义事件会失效,但是原生DOM事件依然有效,比如@click!!!!!!!!!!!!!!
// 其实你可以理解是为什么,因为vue销毁只是那个$vm实例销毁了,他不会代理DOM了,DOM又回到自己
// 初始的样子了,但是你别忘了,没有Vue前,我们自己也是啥都能做的哦
// 3、一般不会在beforDestroy操作数据,因为即便操作数据,也不会再触发更新流程了。
</script>