属性监听器、自定义指令、生命周期函数、注册组件-vue2

文章目录

  • 1、属性监听器watch
    • 1.1定义
    • 1.2运行原理
    • 1.3watch的使用
    • 1.4方法格式VS对象格式
      • 方法格式的监听器:
      • 对象格式的监听器:
    • 1.5watch案例1-进度条监听
    • 1.6watch案例2-汇率案例(newvalue,oldvalue)
  • 2、自定义指令
    • 2.1自定义指令
    • 2.2全局指令
    • 2.3局部指令
    • 2.4注册自定义指令案例
    • 2.5钩子函数
      • 2.5.1 bind
      • 2.5.2 inserted
      • 2.5.3 update
      • 2.5.4 componentUpdated
      • 2.5.5 unbind
      • PS:
    • 2.6钩子函数参数
      • 2.6.1 el
      • 2.6.2 binding
      • 2.6.3 vnode
      • 2.6.4 oldVnode
      • PS
    • 2.7函数简写
  • 3、生命周期函数
    • 3.1定义
    • 3.2各个函数执行的时期
    • 3.3面试题
  • 4、组件
    • 4.1全局组件:
    • 4.2局部组件:
    • 4.3注册组件
      • 4.3.1
      • 4.3.2
      • 4.3.3
      • 4.3.4

1、属性监听器watch

1.1定义

  • watch:{x(){}}中的方法名必须跟要监听的data中的属性名一样,才代表监听指定属性
  • 当侦听器监听的属性发生变化时,就会调用watch中对应的方法
  • 侦听器属性,比计算属性计算效率消耗大

1.2运行原理

  • 修改了引用数据内部的属性值:页面会重新渲染,但是监听属性不会触发
  • 只有修改了引用数据的引用 才能触发侦听器属性,例如
obj: {age: 20}
this.obj={age:"只有修改了引用数据的引用 才能触发侦听器属性"}

obj引用发生变化触发属性监听器

  • 想要修改引用数据内部的属性值也能触发侦听器属性,必须深度监听
             watch: {
					//侦听器属性:必须和data中的数据源同名
					obj: {
						deep: true,
						handler: () => {
							console.log("obj内部的属性改变了")
						}
					}
				}

1.3watch的使用

<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>

1.4方法格式VS对象格式

方法格式的监听器:

缺点:

  • 无法在刚进入页面的时候进行触发,缺少灵活性
  • 如果我们需要监听的是一个对象,那么如果属性中的值发生变化的时候也无法监听到数据的变换

对象格式的监听器:

优点:

  • 可以通过immediate的方法在刚进入页面的时候就可以触发监听
  • 还有一个deep的方法,进行深度监听

            watch:{
                //调用对象格式的监听器
                username:{
                    //侦听器的处理函数
                    handler(newVal,oldVal){
                        console.log(newVal,oldVal);
                    },
                    //表示一进入界面就立即触发一次监听事件,false是默认值
                    immediate:true     
                }
             }

1.5watch案例1-进度条监听

<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>

1.6watch案例2-汇率案例(newvalue,oldvalue)

             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>

2、自定义指令

2.1自定义指令

 除了默认设置的核心指令( v-model 和 v-show 等),Vue 也允许注册自定义指令。
 
在Vue里,代码复用的主要形式和抽象是组件。
然而,有的情况下,仍然需要对纯 DOM 元素进行底层操作,这时候就会用到自定义指令 
。以一个input元素自动获得焦点为例,当页面加载时,使用autofocuse可以让元素将获得
焦点 ,但是autofocuse在移动版Safari上不工作,现在注册一个使元素自动获取焦点的指
令。

指令注册类似于组件注册,包括全局指令和局部指令两种。

2.2全局指令

// 注册一个全局自定义指令 v-focus
Vue.directive('focus', {
  // 当绑定元素插入到 DOM 中。
  inserted: function (el) {
    // 聚焦元素
    el.focus()
  }
})

2.3局部指令

var vm = new Vue({
  el: '#app',
  directives:{
    focus:{
      inserted: function (el) {
        el.focus()
      }      
    }
  }
})

2.4注册自定义指令案例

 <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>

2.5钩子函数

指令定义函数提供了几个钩子函数(可选) 。

2.5.1 bind

只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。

2.5.2 inserted

被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。

2.5.3 update

所在组件的 VNode 更新时调用,但是可能发生在其孩子的 VNode 更新之前。指令的值可能发生了改变也可能没有。但是可以通过比较更新前后的值来忽略不必要的模板更新。

2.5.4 componentUpdated

所在组件的 VNode 及其孩子的 VNode 全部更新时调用。

2.5.5 unbind

只调用一次, 指令与元素解绑时调用。

PS:

  • bind与inserted:bind时父节点为null,inserted时父节点存在;
  • update与componentUpdated:update是数据更新前,componentUpdated是数据更新后。

2.6钩子函数参数

2.6.1 el

指令所绑定的元素,可以用来直接操作 DOM。

2.6.2 binding

一个对象,包含指令名称及该指令所绑定的表达式信息。

2.6.3 vnode

Vue 编译生成的虚拟节点。

2.6.4 oldVnode

上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

PS

  • 除了 el 之外,其它参数都是只读的,尽量不要修改他们。如果需要在钩子之间共享数据,建议通过元素的 dataset 来进行

2.7函数简写

<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!"
})

3、生命周期函数

3.1定义

vm对象的生命周期函数(钩子函数,生命钩子)
相当于是一种特殊事件,当vm实例在整个运行的过程中,会在不同的时期去执行特定的函数,这样的函数就是vue的生命周期函数
beforeCreate created beforeMount mounted destory/x这些钩子都只执行一次
beforeUpdate updated第一次构建不会调用,以后每次data被更新了就会调用
beforeDestroy destroyed 销毁的方式有两种:用户关闭和代码this.$destroy()>销毁vm实例

3.2各个函数执行的时期

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);
            },

属性监听器、自定义指令、生命周期函数、注册组件-vue2_第1张图片

3.3面试题

     //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算法

4、组件

4.1全局组件:

组件的属性不能用大写字母
组件的名字可以用驼峰命名法,但是使用的时候必须用连字符
全局注册的组件使用时不能使用单标签(不会报错,但是只能使用一次 多次使用只显示第一个)
注册的组件不要跟系统标签同名

4.2局部组件:

一个vm实例可以有多个局部组件,但是只能供当前vm实例使用

4.3注册组件

4.3.1

 <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>

4.3.2

<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>

4.3.3

<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>

4.3.4

  <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>

你可能感兴趣的:(vue2,javascript,前端,vue.js)