Object.defineProperty数据代理 &Observer数据劫持
数据代理,通过一个对象代理对另一个对象中属性的操作(读/写)
数据代理+数据劫持 ? 数据的双向绑定(vue中)
Vue 利用 Object.defineProperty 创建一个 observer 来劫持监听所有的属性,把这些属性全部转为 getter 和 setter。
Vue 中每个组件实例都会对应一个 watcher 实例,它会在组件渲染的过程中把使用过的数据属性通过 getter 收集为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。
修改data属性值-》重新解析模板-》生成新的(虚拟)dom-》diff算法对比-》生成更新后页面
TypeScript
let number=10
let person={
name:"lisi",
sex:"男",
age:number,
}
Object.defineProperty(person,"age",{
// value:19,
// enumerable:true,//可枚举
// writable:true //可修改
get(){
debugger
return number
},
set(value){//value为 person.age=1 中的1
debugger
number=value
}
})
person.age=1
// for in 即可遍历数组也可遍历对象
// for (const key in person) {
// if (Object.hasOwnProperty.call(person, key)) {
// const element = person[key];
// console.log(element)
// }
// }
console.log( Object.keys(person))
TypeScript
let obj1={
"x":12
}
let obj2={
name:"lisi",
}
Object.defineProperty(obj2,"x",{
set(value){
obj1.x=value
},
get(){
return obj1.x
}
})
添加class样式
字符串写法
TypeScript
<template>
<div class="hello" :class="a" @click="changeColor()">
{{msg}}
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
},
data(){
return{
a:"red"
}
},
methods:{
changeColor(){
this.a="green"
}
}
}
</script>
数组写法
TypeScript
<div class="hello" :class="classarr" @click="changeColor()">
data(){
return{
classarr:["red","green","orange"]
}
},
对象写法
TypeScript
<div class="hello" :class="classobj" @click="changeColor()">
data(){
return{
classobj:{
"red":true,
"green":false,
"orange":false,
},
}
},
绑定style样式
方式1
TypeScript
<template>
<div class="hello" :style="styleobj" @click="changeColor()">
{{msg}}
</div>
</template>
data(){
return{
styleobj:{
fontSize:"40px"
}
}
},
方式2
TypeScript
<div class="hello" :style="{fontSize:fontsize}" @click="changeColor()">
方式3
:style[a,b]
a和b为样式对象 如:
styleobj:{
fontSize:"40px"
}
v-if
TypeScript
<div v-if="n===1">1</div>
<div v-else-if="n===2">1</div>
<div v-else-if="n===3">1</div>
<div v-else>1</div>
计算属性
计算属性回调函数
2个时刻调用:初始化和方法里面的数据改动
TypeScript
<template>
<div class="hello" >
<input type="text" v-model="inputtext">
<button @click="sortAge=1">年龄升序</button>
<button @click="sortAge=2">年龄降序</button>
<button @click="sortAge=0">原顺序</button>
<ul >
<li v-for="item in filperson" :key="item.id">
{{ item.name }} ------ {{ item.age }}
</li>
</ul>
</div>
</template>
<script>
/* eslint-disable */
import { watch } from 'vue';
export default {
name: 'HelloWorld',
props: {
msg: String
},
data(){
return{
sortAge:0,//1升序,2降序,0原顺序
arr:[
{"id":"1","name":"lisi1","age":12},
{"id":"2","name":"lisi2","age":11},
{"id":"3","name":"wangwu1","age":33},
{"id":"4","name":"wang2","age":55}
],
endarr:[],
inputtext:""
}
},
methods:{
},
computed:{
// 默认执行一次,this.inputtext发生变化则计算一次
filperson(){
let starr= this.arr.filter((item)=>{
return item.name.includes(this.inputtext)
})
if(this.sortAge){
debugger
starr.sort((a,b)=>{
return this.sortAge==1?a.age-b.age :b.age-a.age
})
}
return starr
}
},
}
</script>
条件过滤
TypeScript
<template>
<div class="hello" >
<input type="text" v-model="inputtext">
<ul>
<li v-for="item in endarr" :key="item.id">
{{ item.name }}
</li>
</ul>
</div>
</template>
<script>
/* eslint-disable */
import { watch } from 'vue';
export default {
name: 'HelloWorld',
props: {
msg: String
},
data(){
return{
arr:[
{"id":"1","name":"lisi1"},
{"id":"2","name":"lisi2"},
{"id":"2","name":"wangwu1"},
{"id":"3","name":"wang2"}
],
endarr:"",
inputtext:""
}
},
methods:{
},
watch:{
// 简写形式
// inputtext(newvalue){
// this.endarr= this.arr.filter((item)=>{
// return item.name.includes(newvalue)
// })
// }
// 完整形式
inputtext:{
// 初始化的时候立即执行
immediate:true,
handler(newvalue){
this.endarr= this.arr.filter((item)=>{
return item.name.includes(newvalue)
})
}
}
}
}
</script>
后期给对象添加属性
TypeScript
<template>
<div class="hello" >
<p>姓名:{{person.name}}</p>
<p>姓名:{{person.age}}</p>
<button @click="updata"> person添加属性</button>
</div>
</template>
<script>
/* eslint-disable */
import Vue, { watch } from 'vue';
// import Vue from 'vue/types/umd';
// import { person } from '../../../hellovue3/src/types/index';
export default {
name: 'HelloWorld',
props: {
msg: String
},
data(){
return{
person:{
"name":"lisu",
}
}
},
methods:{
updata(){
// 方法1
// Vue.set(this.person,"age","boo")//只可给data里面的对象上添加属性,不可给data添加
// 方法2
this.$set(this.person,"age","boo")
}
},
}
</script>
收集表单里面的信息
TypeScript
<template>
<div class="hello" >
<!-- prevent组织默认刷新行为 -->
<form @submit.prevent="sub">
账号:<input type="text" v-model.trim="person.acount"><br/><br/>
密码:<input type="password" v-model="person.password"><br/><br/>
年龄:<input type="number" v-model.number="person.age"><br/><br/>
性别:<label for="nan">男</label> <input v-model="person.personSex" type="radio" name="sex" id="nan" value="male">
<label for="nv">女</label> <input v-model="person.personSex" type="radio" name="sex" id="nv" value="famale"><br/><br/>
爱好:学习<input type="checkbox" v-model="person.like" value="lea">
打游戏<input type="checkbox" v-model="person.like" value="dyx">
吃美食<input type="checkbox" v-model="person.like" value="cms"><br/><br/>
喜欢城市:<select name="" v-model="person.city" aria-placeholder="请选择喜欢的城市" id="">
<option value="1">上海</option>
<option value="2">北京</option>
<option value="3">深圳</option>
<option value="4">广州</option>
</select><br/><br/>
<!-- v-model.lazy失去焦点更新数据 -->
其他信息:<textarea name="" v-model.lazy="person.other" id="" cols="30" rows="10">
</textarea><br/><br/>
<!--checkbox不设置value值 则是否打勾为true或者false -->
<input type="checkbox" v-model="person.agree">我同意<br/><br/>
<button>提交</button>
</form>
</div>
</template>
<script>
import Vue, { watch } from 'vue';
export default {
name: 'HelloWorld',
props: {
msg: String
},
data(){
return{
person:{
acount:"",
password:"",
like:[],
personSex:"",
city:"",
age:0,
other:"",
agree:''
},
}
},
methods:{
sub(){
console.log("提交")
console.log(JSON.stringify(this.person))
}
},
}
</script>
v-html指令安全问题
cookie中 k1 ,k2的值被篡改,则不安全;
被其他网站获取到也不安全,获取到可直接登录(httponly可避免通过代码获取cookie)
指令
v-clock
指令+样式 当网络延迟时,动态渲染的页面字段不显示,当页面渲染结束后,vue自动删除v-clock
TypeScript
<template>
<div class="hello" >
<p v-cloak>{{name}}</p>
<p v-cloak>{{age}}</p>
</div>
</template>
<script>
/* eslint-disable */
import Vue, { watch } from 'vue';
export default {
name: 'HelloWorld',
props: {
msg: String
},
data(){
return{
name:"1111",
age:"2"
}
},
methods:{
},
}
</script>
<style scoped>
[v-cloak]{
display: none;
}
.hello{
width: 100%;
height: 100px;
/* border: 1px solid #dedede; */
text-align: left;
}
</style>
v-pre
跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。
v-once 只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。
自定义指令
自定义指令的两种实现方式
TypeScript
<template>
<div class="hello" >
<!-- 指令v-big,num放大10倍 -->
<!-- v-focus 页面刷新时得到焦点 -->
<p >{{num}}</p>
<!-- 放大10倍后的n -->
<p v-big="num"></p>
<button @click="num++">num加一</button><br/>
<input v-focus="num" type="text"><br/>
<input v-big-number="num" type="text">
</div>
</template>
<script>
/* eslint-disable */
import Vue, { watch } from 'vue';
// 全局自定义指令两种方法
// Vue.directive("big",function (element,binding){
// element.innerText=binding.value*10
// })
// Vue.directive("focus",{
// // 指令和元素成功绑定时(一上来,并不是放入页面时)
// bind(element,binding){
// element.value=binding.value
// },
// // 指令所在元素被插入页面时
// inserted(element,binding){
// element.focus()
// },
// // 指令所在的模板被从新解析时
// update(element,binding){
// element.value=binding.value
// }
// })
export default {
name: 'HelloWorld',
props: {
msg: String
},
data(){
return{
num:1,
}
},
methods:{
},
directives:{
// big函数何时会被调用?
// 1.指令和元素成功绑定时(一上来,并不是放入页面时)
// 2.指令所在的模板被从新解析时
big(element,binding){
element.innerText=binding.value*10
},
focus:{
// 指令和元素成功绑定时(一上来,并不是放入页面时)
bind(element,binding){
element.value=binding.value
},
// 指令所在元素被插入页面时
inserted(element,binding){
element.focus()
},
// 指令所在的模板被从新解析时
update(element,binding){
element.value=binding.value
}
},
'big-number'(element,binding){
console.log(element,binding.value)
element.value=binding.value*10
}
}
}
</script>
<style scoped>
[v-cloak]{
display: none;
}
.hello{
width: 100%;
height: 100px;
/* border: 1px solid #dedede; */
text-align: left;
}
</style>