Vue——数据绑定(面试)--响应式数据、双向数据绑定、过滤器(面试)

发布于:2023-01-04 ⋅ 阅读:(436) ⋅ 点赞:(0)

目录

一、数据绑定(面试)--响应式数据、双向数据绑定

 1)响应式数据:

1、响应式数据概念:

 2、响应式数据的原理——笔试题写代码

3、笔试题

2)双向数据绑定:

1、双向数据绑定概念:

2、双向数据绑定的实现: 2种方式

3、响应式数据设计原理:

4、面试题

二、过滤器(面试)


一、数据绑定(面试)--响应式数据、双向数据绑定

先执行{{msg}},再执行v-html,所以{{msg}}会被替换

js对象的成员添加三种方式:

obj.age=10                 obj["name"]="karen"

            Object.defineProperty(obj,"birth",{

                set(){},

                get(){}

            })

 1)响应式数据:

1、响应式数据概念:

只能由代码改变UI或者只能由UI改变代码

( 如果内存中的数据变化了 页面UI也会动态跟着刷新  这种数据就是响应式数据)

什么vue的响应式数据:

采用数据劫持方式,即 Object.defineProperty() 劫持 data 中各属性,实现响应式数据

若 data 中某属性多次发生变化,watcher 仅会进入更新队列一次

 

2、响应式数据的原理——笔试题写代码

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.14/vue.js"></script>					  
	</head>
	<body>
		<div id="app">
			<!-- <h1 v-html="title">{{msg}}</h1> -->
			<h1 v-html="title"></h1> 
			<p>{{msg}}</p>
			<button @click="fn">change1</button>
		</div>
		<script>
			var vm=new Vue({
				el:"#app",
				data:{
					title:"hello",
					msg:"666"
				},
				methods:{
					fn(){
						for(let i=0;i<10000;i++){
							this.title=i
						}					
					}
				}
			})			
		</script>
		<div id="myapp">
			<h1 id="title"></h1> 
			<p id="msg"></p>
		</div>
		<script>
			function MyVue(option){
				let _myvm={}
				//劫持
				let arr=Object.keys(option.data)//["title","msg"]
				// _myvm[arr[0]]=option.data[arr[0]]
				// _myvm[arr[1]]=option.data[arr[1]]
				for(let i=0;i<arr.length;i++){
					 Object.defineProperty(_myvm,arr[i],{
						 set(v){
							 //劫持
							 option.data[arr[i]]=v
							 //响应-刷新页面
							 let title=document.querySelector(option.el+" #title")
							 let msg=document.querySelector(option.el+" #msg")
							 title.innerHTML=_myvm["title"]
							 msg.innerHTML=_myvm["msg"]
						 },
						 get(){
							 return option.data[arr[i]]
						 }
					 })
					 _myvm[arr[i]]=option.data[arr[i]]
				}							
				return _myvm
			}
			var myvm=new MyVue({
				el:"#myapp",
				data:{
					title:"mytitle66666",
					msg:"mymsg666666",
					obj:{age:10,name:"karen"},
					arr:[10,230,5]
				}
			})			
		</script>		
	</body>
</html>

3、笔试题

1、对于 Vue 中响应式数据原理的说法,下列哪项是不正确的?

A. 采用数据劫持方式,即 Object.defineProperty() 劫持 data 中各属性,实现响应式数据
B. 视图中的变化会通过 watcher 更新 data 中的数据
C. 若 data 中某属性多次发生变化,watcher 仅会进入更新队列一次
D. 通过编译过程进行依赖收集

选择B:视图中的变化会通过 watcher 更新 vm中或者this中 的数据

(一般程序员会说data是数据源,所以就更新data,但是正确的是更新vm)

选择D: 通过编译过程进行依赖收集

数组的函数可以劫持

数组的下标不能劫持

(解决方法:

1、this.$set

2、Vue.set

3、刷新页面中的无关紧要的变量,比如:this.msg="原本的内容" ,程序员常用,但是不是官方的解决方法)

Vue 中的数组变更通知,通过拦截数组操作方法而实现

 

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title></title>
</head>
<body>
	<script type="text/javascript">
	</script>
	<script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.14/vue.js"></script>
	<div id="app">
		<!-- <h1 v-html="title">{{msg}}</h1> -->
		<h1 v-html="title"></h1>
		<p>{{msg}}</p>
		<p>{{person.age}}</p>
		<p>{{arr[2]}}</p>
		<button @click="fn">change1</button>
		<button @click="look">look</button>
	</div>
	<script>
		var vm = new Vue({
			el: "#app",
			data: {
				title: "hello",
				msg: "666",
				person: { age: 20 },
				arr: [102, 200, 300]
			},
			methods: {
				fn() {
					// this.person.age=30
					// this.arr[2]="hello"
                    //没有劫持数组的下标(不能刷新页面),但是look里面会打印hello
					// this.arr.splice(2,1,"hello")//劫持了数组的方法(可以刷新页面)				
					// Vue.set(this.arr,2,"hello")//vue帮我们刷新页面
					this.$set(this.arr, 2, "hello")//vue帮我们刷新页面
				},
				look() {
					console.log(this.arr[2])
				}
			}
		})
	</script>
</body>
</html>

2)双向数据绑定:

1、双向数据绑定概念:

代码改变UI,UI也能改变代码

双向数据绑定的概念要包括响应式数据绑定,所以要先说响应式数据绑定概念

(如果数据容器中的数据变了也会让页面刷新(DOM操作让页面改变)

如果用户操作DOM,改变了页面,反之也会让数据容器中的数据值改变)

2、双向数据绑定的实现: 2种方式

1.自己实现,vue可以自己实现(没必要)  微信开发可以自己实现(只能自己实现)
利用input事件,用户交互的时候,获取用户输入的值,然后把值绑定到data容器中

2.系统指令:v-model

mode是语法糖

<input type="text" :value="msg" @input="myinput">

<input type="text" v-mode="msg">

v-mode="msg" 是 :value="msg" @input="myinput"的合成

3、响应式数据设计原理:

vue2.0:vue实现数据双向绑定主要是:采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应监听回调。当把一个普通 Javascript 对象传给 Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,用 Object.defineProperty 将它们转为 getter/setter。用户看不到 getter/setter,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。

  vue3.0 --使用es6 proxy 代理了data对象

//利用 Object.defineProperty 自己实现双向数据绑定
<body>
    <div id="app">
      <input type="text" id="txt">
      <p id="show"></p>
    </div>
</body>
<script type="text/javascript">
    var obj = {}
    Object.defineProperty(obj, 'txt', {
        get: function () {
            return obj['txt']
        },
        set: function (newValue) {
            document.getElementById('txt').value = newValue
            document.getElementById('show').innerHTML = newValue
        }
    })
    document.addEventListener('keyup', function (e) {
        obj.txt = e.target.value
    })
</script>
<!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>
</head>
<body>
    <div id="app">
        <button @click="change1">改变数据容器中的数据</button>
        <button @click="look"></button>
        <p>{{msg}}</p>
        <input type="text" :value="msg" @input="myinput">
        <!-- 下面一行代码是上面一行代码的合成  -->
        <input type="text" v-model="msg">  
    </div>
    <script>
        new Vue({
            el:"#app",
            data:{
                msg:"hello"
            },
            methods: {
                change1(){
                    this.msg="666"   //底层:在执行this对象(vm)的msg的set
                },
                look(){
                    console.log(this.msg)
                },
                myinput(e) {
                    this.msg=e.target.value
                }
            },
        })
    </script>
</body>
</html>

 

4、面试题——

下列关于 v-model 的说法,哪项是不正确的?
A. v-model 能实现双向绑定
B. v-model 本质上是语法糖,它负责监听用户的输入事件以更新数据
C. v-model 是内置指令,不能用在自定义组件上
D. 对 input 使用 v-model,实际上是指定其 :value 和 :input

选择:C:能用在自定义组件上

选择:D.:对 input 使用 v-model,实际上是指定其 :value 和 @input  (:oninput)

二、过滤器(面试)

filter主要用于数据展示之前的处理 过滤器只能用在v-bind或者插值表达式中 语法:

  <div id="app">
        <div v-for="(item) in sinaArr" class="box">
            <p v-html="item.user.name"></p>
            <img :src="item.user.img">
            <p v-text="item.text"></p>
            <!-- <p>发表时间:{{item.create_At|timerTool}}</p> -->

            <!-- 下面这种写法是不行的:过滤器只能应在v-bind或者插值表达式中 -->
            <p v-html="item.create_At|timerTool">发表时间:</p>
        </div>
    </div>

    <script>
        new Vue({
            el: "#app",
            data: {
                sinaArr: [{ create_At: "Thu Apr 16 14:08:18 +0800 2020", text: "内容1", user: { name: "karen1", img: "1.jpg" } },
                { create_At: "Thu Apr 16 14:01:18 +0800 2020", text: "内容2", user: { name: "karen2", img: "2.jpg" } },
                { create_At: "Thu Apr 16 10:39:18 +0800 2020", text: "内容3", user: { name: "karen3", img: "3.jpg" } },
                { create_At: "4.jpg" }]
            },
            filters: {
                timerFormat(arg) {
                    var dt1 = new Date(arg)
                    var dt2 = new Date()
                    var abstime = dt2 - dt1
                    if (0 <= abstime && abstime < 1000 * 60) {
                        return "刚刚"
                    } else if (1000 * 60 <= abstime && abstime < 1000 * 60 * 60) {
                        var m = new Date(abstime).getMinutes() + ""
                        return `${m}分钟前`
                    } else if (1000 * 60 * 60 <= abstime && dt1.getDate() == dt2.getDate()) {
                        var m = dt1.getMinutes() + ""
                        var h = dt1.getHours()
                        return `今天 ${h}:${m.padStart(2, "0")}`
                    } else if ((dt1.getDate() + 1) == dt2.getDate()) {
                        var m = dt1.getMinutes() + ""
                        var h = dt1.getHours()
                        return `昨天 ${h}:${m.padStart(2, "0")}`
                    } else if ((dt1.getDate() + 2) == dt2.getDate()) {
                        var m = dt1.getMinutes() + ""
                        var h = dt1.getHours()
                        return `前天 ${h}:${m.padStart(2, "0")}`
                    }
                }
            }
        })
    </script>
<div id="app">
		<p>{{a}}</p>
		<p>{{timerformatter(birth)}}</p>
		<p>{{birth|tool|tool2}}</p>   <!-- birth作为参数传入tool函数,然后结果再作为参数传给tool2-->
		<p>{{birth|tool3(100,200)}}</p>
        <!--birth是第一个参数,100,200是第二、三个参数-->
		<a :href="url|tool4">baidu</a>
		<!-- <p v-text="birth|tool3"></p>   不能用在这里 -->
		<button @click="change1">change1</button>
	</div>
	<script>
		var vm = new Vue({
			el: "#app",
			data: {
				a: "测试",
				birth: "2007-02-03",
				url: "www.baidu.com"
			},
			methods: {
				change1() {
					this.a = "66666"
				},
				timerformatter(str) {
					console.log("调用了函数timerformatter--methods")
					let age = new Date().getFullYear() - new Date(str).getFullYear()
					return age + "岁"
				}
			},
			filters: {
				tool(str) {
					console.log("调用了函数tool--filters")
					let age = new Date().getFullYear() - new Date(str).getFullYear()
					return age + "岁"
				},
				tool2(str) {
					if (parseInt(str) > 18) {
						return "可以喝酒:" + str
					} else {
						return "禁止进入:" + str
					}
				},
				tool3(arg1, arg2, arg3) {
					console.log(arg1, arg2, arg3)
					return "hello"
				},
				tool4(url) {
					return "http://" + url
				}
			}
		})
	</script>