obj: {age: 20}
this.obj={age:"只有修改了引用数据的引用 才能触发侦听器属性"}
obj引用发生变化触发属性监听器
watch: {
//侦听器属性:必须和data中的数据源同名
obj: {
deep: true,
handler: () => {
console.log("obj内部的属性改变了")
}
}
}
<div id='app'>
<p>{{n}}</p>
<button @click="change1">修改n</button>
<p>{{obj.age}}</p>
<button @click="change2">修改obj</button>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
n: 100,
obj: {
age: 20
}
},
methods: {
change1() {
console.log("点击事件触发了")
this.n = "修改了"
},
change2() {
// this.obj.age="修改了引用数据内部的属性值:页面会重新渲染,但是侦听器属性不会触发"
// this.obj={age:"只有修改了引用数据的引用 才能触发侦听器属性"}
this.obj.age = "修改了引用数据内部的属性值也想触发侦听器属性,必须深度监听"
}
},
watch: {
//侦听器属性:必须和data中的数据源同名
n() {
console.log(666666666)
},
// obj(){
// console.log("obj改变了")
// }
obj: {
deep: true,
// 监听器函数在初始渲染时并不会被调用,只有在后续监听的属性发生变化时才会被调用;
// 如果要让监听器函数在监听后立即执行,可以使用immediate选项,设为true。
immediate: true,
handler: () => {
console.log("obj改变了")
}
}
}
})
</script>
缺点:
优点:
watch:{
//调用对象格式的监听器
username:{
//侦听器的处理函数
handler(newVal,oldVal){
console.log(newVal,oldVal);
},
//表示一进入界面就立即触发一次监听事件,false是默认值
immediate:true
}
}
<style type="text/css">
.slider{
width:400px;
height: 20px;
background-color: skyblue;
position: relative;
left: 100px;
top: 100px;
border-radius: 10px;
}
.sliderbar{
width:30px;
height: 30px;
border-radius: 50%;
background-color:cadetblue;
position: relative;
/* left:370px, */
top: -5px;
}
</style>
<div id='app'>
进度条:{{total-currenttime|timerparser}}
<div class="slider">
<div class="sliderbar" :style="{left:x}"></div>
</div>
<button @click="start">start</button>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
currenttime:0,
total:242,
x:0,
maxwidth:370
},
methods: {
start(){
this.timer=setInterval(()=>{
this.currenttime+=0.1
},100)
}
},
filters:{
timerparser(arg){
return ` ${parseInt(arg/60).toString().padStart(2,"0")}:${parseInt(arg%60).toString().padStart(2,"0")}`
}
},
watch:{
currenttime(value){
//x:370 currenttime:240
this.x=this.maxwidth*value/this.total+"px"
// console.log(this.x)
if(value>=60){
clearInterval(this.timer)
alert("试听结束")
}
}
}
})
</script>
watch:{
rmb(newvalue,oldvalue){
console.log(arguments)
this.doller=(newvalue/6.9).toFixed(2)*100/100
},
doller(newvalue,oldvalue){
this.rmb=newvalue*6.9
}
}
<div id='app'>
RMB:<input type="text" v-model="rmb">
doller:<input type="text" v-model="doller">
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
rmb:0,
doller:0
},
methods: {},
watch:{
rmb(newvalue,oldvalue){
console.log(arguments)
this.doller=(newvalue/6.9).toFixed(2)*100/100
},
doller(newvalue,oldvalue){
this.rmb=newvalue*6.9
}
}
})
</script>
除了默认设置的核心指令( v-model 和 v-show 等),Vue 也允许注册自定义指令。
在Vue里,代码复用的主要形式和抽象是组件。
然而,有的情况下,仍然需要对纯 DOM 元素进行底层操作,这时候就会用到自定义指令
。以一个input元素自动获得焦点为例,当页面加载时,使用autofocuse可以让元素将获得
焦点 ,但是autofocuse在移动版Safari上不工作,现在注册一个使元素自动获取焦点的指
令。
指令注册类似于组件注册,包括全局指令和局部指令两种。
// 注册一个全局自定义指令 v-focus
Vue.directive('focus', {
// 当绑定元素插入到 DOM 中。
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
var vm = new Vue({
el: '#app',
directives:{
focus:{
inserted: function (el) {
el.focus()
}
}
}
})
<div id="box">
<h1 v-red>{{rwx1}}</h1>
<h2 v-yellow>{{rwx2}}</h2>
<input type="text" v-focus v-blue="gaibiancolor" v-model="rwx3" />
<h2 v-blue="gaibiancolor">{{rwx3}}</h2>
</div>
<script>
new Vue({
el: "#box",
data: {
rwx1: "自定义指令1",
rwx2: "自定义指令2",
rwx3: "自定义指令3",
gaibiancolor: "green",
},
methods: {},
filters: {},
watch: {},
directives: {
red: {
inserted(el) {
el.style.color = "red";
},
},
yellow: {
inserted(el) {
el.style.color = "yellow";
},
},
focus: {
inserted(el) {
el.focus();
},
},
blue: {
inserted(el, option) {
el.style.color = option.value;
},
},
},
});
</script>
指令定义函数提供了几个钩子函数(可选) 。
只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。
被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。
所在组件的 VNode 更新时调用,但是可能发生在其孩子的 VNode 更新之前。指令的值可能发生了改变也可能没有。但是可以通过比较更新前后的值来忽略不必要的模板更新。
所在组件的 VNode 及其孩子的 VNode 全部更新时调用。
只调用一次, 指令与元素解绑时调用。
指令所绑定的元素,可以用来直接操作 DOM。
一个对象,包含指令名称及该指令所绑定的表达式信息。
Vue 编译生成的虚拟节点。
上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
<div v-demo="{ color: 'white', text: 'hello!' }"></div>
Vue.directive('demo', function (el, binding) {
console.log(binding.value.color) // => "white"
console.log(binding.value.text) // => "hello!"
})
vm对象的生命周期函数(钩子函数,生命钩子)
相当于是一种特殊事件,当vm实例在整个运行的过程中,会在不同的时期去执行特定的函数,这样的函数就是vue的生命周期函数
beforeCreate created beforeMount mounted destory/x这些钩子都只执行一次
beforeUpdate updated第一次构建不会调用,以后每次data被更新了就会调用
beforeDestroy destroyed 销毁的方式有两种:用户关闭和代码this.$destroy()>销毁vm实例
beforeCreate() {
//能否网络请求?
//能做网络请求,因为这是函数在运行时XMLHttpRequest是可以访问并且去做AJAX请求的
//能否网络请求数据 然后设置到数据源中?
//不能设置到数据源中,因为这个钩子中 this还在创建
//这个在项目中干什么?
//只要不是用于页面渲染
//预加载图片: 网页中同源加载的优化(同一个页面中img script等等 src属性去请求资源)
new Image().src =
"https://img1.baidu.com/it/u=1966616150,2146512490&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1662397200&t=873657ddc05e966309998f18814a9e54";
//预加载工具
//第三方工具的加载
//这个函数在运行时 vm正在创建中:劫持data,methods 也就是 this对象中还不能访问到数据
console.log("beforeCreate", this.msg, this.change1, this);
},
created() {
//能否网络请求?
//能做网络请求,因为这是函数在运行时XMLHttpRequest是可以访问并且去做AJAX请求的
//能否网络请求数据 然后设置到数据源中?
//可以设置到数据源中,因为这个钩子中 this已经创建完毕了
//这个在项目中干什么?
//请求首屏数据
//vm对象已经创建完毕了,但是它(vm)还没有挂载到DOM树中
//这个函数可以操作this对象了 但是无法操作DOM
console.log("created", this.msg, this.change1);
},
beforeMount() {
//渲染前的操作
//vm对象已经创建完毕了,在挂载之前触发的钩子
//这个函数可以操作this对象了 但是无法操作DOM
console.log("beforeMount");
},
mounted() {
//vm已经挂载到页面了
//请求首屏数据,请求时页面已经出来了
console.log("mounted");
},
beforeUpdate() {
//这两个钩子中 不能网络请求新数据 去更新数据源
//会导致死循环
//数据源已经更新了,页面重新渲染前(并不是数据更新前) 触发的钩子
console.log("beforeUpdate", this.url);
},
updated() {
//页面已经重新渲染了触发的钩子
console.log("updated");
},
beforeDestroy() {
//vm对象销毁之前触发的钩子,this还在 可以做最后的操作
//保存用户的行为配置文件:播放器的进度 等等
console.log("beforeDestroy", this.msg);
},
destroyed() {
//后面在webpack环境下操作 无法操作this
//往往把当前组件中计时器清除了 可以把body的滚动条滚到顶部
console.log("destroyed", this.msg);
},
//1.什么是生命周期函数?
//vue组件对象在创建到销毁的过程中,在某一种条件成立的时刻 系统会去调用的vue中设定的函数 这些函数都叫做:生命周期函数
//2.vue的命周期函数有哪些?
//普遍的答法:有8个创建前后,挂载前后,更新前后,销毁前后
//高级的答法:
//组件的有8个(创建前后,挂载前后,更新前后,销毁前后)
//自定义指令也有5个
//动态组件有2个 -后面讲
//路由(组件有3个,全局有2个,独享有1个) -后面讲
//3.为什么设计生命周期函数?
//为了更好的设计程序,让代码更有逻辑 和 可维护性
//4.页面首次加载过程中,会依次触发哪些钩子
//beforeCreate,created,beforeMount,mounted
//5. this.$el 是什么?它在哪些钩子中才能访问?
//它代表了当前组件的真实DOM,要在mounted之后才有
//6. Vue 实例的 data 属性,在哪些钩子中能访问
//created beforeMount mounted beforeUpdate updated beforeDestroy
//7.为什么不要在更新钩子中做页面的数据请求?
//会导致死循环 react有一个shoudComponentUpdate可以自己控制 但是vue没有
//8.你用beforeCreate做过什么业务?
//这个钩子中可以做网络请求 但是vm没有构建完毕,此时数据方法等等的劫持还没有完成,不能操作this,因此可以做预加载.
//9.VM和DOM之间的关系?
//9.1.VM是JS模拟出来的跟DOM结构很像的一种对象结构VNode. 它通过底层的render函数渲染到页面上,让页面DOM跟虚拟VNode关联映射.
//9.2 如果VM的数据源发生变化,会让内存中生成新的VNode 新的VNode会和旧的VNode作比较然后更新,这个过程就是DIFF算法
组件的属性不能用大写字母
组件的名字可以用驼峰命名法,但是使用的时候必须用连字符
全局注册的组件使用时不能使用单标签(不会报错,但是只能使用一次 多次使用只显示第一个)
注册的组件不要跟系统标签同名
一个vm实例可以有多个局部组件,但是只能供当前vm实例使用
<div id="box">
<Hll></Hll>
<Rwx></Rwx>
<Wl></Wl>
<Zwq></Zwq>
</div>
<script>
new Vue({
el: "#box",
data: {},
methods: {},
filters: {},
watch: {},
directives: {},
components: {
Hll: {
template: `
Hll
这是组件1
`,
},
Rwx: {
template: `
Rwx
这是组件2
`,
},
Wl: {
template: `
Wl
这是组件3
`,
},
Zwq: {
template: `
Zwq
这是组件4
`,
},
},
});
</script>
<div id="box">
<Hll></Hll>
<Rwx></Rwx>
<Wl></Wl>
<Zwq></Zwq>
</div>
<script>
let hll = {
template: `
Hll
这是组件1
`,
};
let rwx = {
template: `
Rwx
这是组件2
`,
};
let wl = {
template: `
Wl
这是组件3
`,
};
let zwq = {
template: `
Zwq
这是组件4
`,
};
new Vue({
el: "#box",
data: {},
methods: {},
filters: {},
watch: {},
directives: {},
components: {
Hll: hll,
Rwx: rwx,
Wl: wl,
Zwq: zwq,
},
});
</script>
<div id="box">
<Hll></Hll>
<Rwx></Rwx>
<Zwq></Zwq>
</div>
<script type="module">
// 导入
import hll from "./components/Hll.js";
import rwx from "./components/Rwx.js";
import zwq from "./components/Zwq.js";
new Vue({
el: "#box",
data: {},
methods: {},
filters: {},
watch: {},
directives: {},
components: {
Hll: hll,
Rwx: rwx,
Zwq: zwq,
},
});
</script>
<div id="box">
<Hll></Hll>
<Rwx></Rwx>
<Zwq></Zwq>
<bigbox></bigbox>
</div>
<script type="module">
// 导入
import hll from "./components/Hll.js";
import rwx from "./components/Rwx.js";
import zwq from "./components/Zwq.js";
new Vue({
el: "#box",
data: {},
methods: {},
filters: {},
watch: {},
directives: {},
components: {
Hll: hll,
Rwx: rwx,
Zwq: zwq,
bigbox: {
template: `
666-box2
{{msg}}
`,
data: function () {
return { msg: "msg66666" };
},
methods: {
fn() {
console.log("bigbox组件的方法");
},
},
filters: {},
watch: {},
computed: {},
directives: {},
beforeCreate() {},
created() {},
beforeMount() {},
mounted() {},
beforeUpdate() {},
updated() {},
beforeDestroy() {},
destroyed() {},
},
},
});
</script>