文章目录
- 自动创建项目
- 代码分析
- 响应式原理-代理
- data详解
- methods
- computed
自动创建项目
npm init vue@latest
yarn create vue
yarn
yarn dev
代码分析
- data是一个函数
- 在data中,this就是当前的组件实例vm
- 如果使用箭头函数,则无法通过this来访问组件实例
- 使用vue时,减少使用箭头函数
- data会返回一个对象作为返回值,vue会对该对象进行代理
- 从而将其转换为响应式数据,响应式数据可以直接通过组件实例访问
- 直接向组件实例中添加的属性不会被vue所代理,不是响应数据,修改后页面不会发生变化
vm.$data
是实际的代理对象,通过vm可以直接访问到$data
中的属性vm.$data.msg
等价于vm.msg
<script>
// const obj = {
// msg:"哈哈,我是obj"
// }// window.obj = obj// 组件,一个组件可以创建多个组件实例
// 组件就是一个普通的js对象
export default {// data是一个函数// 在data中,this就是当前的组件实例vm// 如果使用箭头函数,则无法通过this来访问组件实例// 使用vue时,减少使用箭头函数// data: vm => {// console.log("data", vm)// return {// msg: "我爱Vue"// }// }data() {// console.log("data", this)// 直接向组件实例中添加的属性不会被vue所代理,不是响应数据,修改后页面不会发生变化// this.name = "孙悟空"// vm.$data 是实际的代理对象,通过vm可以直接访问到$data中的属性// vm.$data.msg 等价于 vm.msg// data会返回一个对象作为返回值,vue会对该对象进行代理// 从而将其转换为响应式数据,响应式数据可以直接通过组件实例访问return {msg: "我爱Vue"}// return obj},created(){// 会在组件创建完毕后调用// 可以通过vm.$data动态的向组件中添加响应式数据,但是不建议这么做this.$data.name = "孙悟空"}
}
</script><template><h1>{{ msg }}</h1><h2>{{ name }}</h2>
</template>
App.vue是根组件
- createApp(App) 将根组件关联到应用上
- 会返回一个应用的实例
- app.mount(“#app”) 将应用挂载到页面中
- 会返回一个根组件的实例,组件的实例通常可以命名为vm
- 组件实例是一个Proxy对象(代理对象)
main.js
import { createApp } from 'vue'
import App from './App.vue'/* App.vue是根组件- createApp(App) 将根组件关联到应用上- 会返回一个应用的实例- app.mount("#app") 将应用挂载到页面中- 会返回一个根组件的实例,组件的实例通常可以命名为vm- 组件实例是一个Proxy对象(代理对象)*/
const app = createApp(App)const vm = app.mount("#app")// 将vm设置为全局变量
window.vm = vm
window.app = app// createApp(App).mount('#app')// console.log(vm)
响应式原理-代理
/* 如果直接修改对象的属性,那么就是仅仅修改了属性,没有去做其他的事情,这种操作只会影响对象自身,不会导致元素的重新的渲染希望在修改一个属性的同时,可以进行一些其他的操作,比如触发元素重新渲染!要实现这个目的,必须要对对象进行改造,vue3中使用的是的代理模式来完成对象的改造设置代理时不会对原对象产生影响!
*/
// obj.name = "猪八戒"// 创建一个对象
const obj = {name: "孙悟空",age: 18
}// 来为对象创建一个代理
const handler = {// get用来指定读取数据时的行为,它的返回值就是最终读取到的值// 指定get后,在通过代理读取对象属性时,就会调用get方法来获取值get(target, prop, receiver) {// 返回值之前做一些其他的操作...// 在vue中,data()返回的对象会被vue所代理// vue代理后,当我们通过代理去读取属性时,返回值之前,它会先做一个跟踪的操作// 当我们通过代理去修改属性时,修改后,会通知之前所有用到该值的位置进行更新// track() 追踪谁用了我这个属性/* 三个参数:target 被代理的对象prop 读取的属性receiver 代理对象*/return target[prop]},// set会在通过代理修改对象时调用set(target, prop, value, receiver){target[prop] = value// trigger() 触发所有的使用该值的位置进行更新// 值修改之后做一些其他的操作}
} // handler 用来指定代理的行为// 创建代理
const proxy = new Proxy(obj, handler)// 修改代理的属性
proxy.age = 28console.log(proxy.age)
data详解
- vue在构建响应式对象时,会同时将对象中的属性也做成响应式属性。即深层响应式对象
- 有些场景下,可以通过shallowReactive()来创建一个浅层的响应式对象。只能响应式修改第一层的值
- 建议将那些暂时没有使用到的属性,也添加到data返回的对象中,值可以设置为null
- /数组也是响应式数据
<script>
import MyButton from "./components/MyButton.vue"
import { shallowReactive } from "vue"export default {data() {// data返回的对象最终会被Vue所代理// this.$data.xxx = "xxx" 动态添加响应数据(不建议这么做)// 建议将那些暂时没有使用到的属性,也添加到data返回的对象中,值可以设置为nullreturn {msg: "今天天气真不错!",// vue在构建响应式对象时,会同时将对象中的属性也做成响应式属性// 深层响应式对象stu: {name: "孙悟空",age: 18,gender: "男",friend: {name: "猪八戒"}},hello: null// 数组也是响应式数据arr: ["孙悟空", "猪八戒", "沙和尚"]}// 有些场景下,可以通过shallowReactive()来创建一个浅层的响应式对象// 只能响应式修改第一层的值// return shallowReactive({// msg: "大闸蟹今天没去玩游戏!",// stu: {// name: "孙悟空",// age: 18,// gender: "男",// friend: {// name: "猪八戒"// }// }// })},components: {MyButton}
}
</script>
<template><h1>{{ msg }}</h1><h2>{{ stu.name }} -- {{ stu.age }} -- {{ stu.gender }}</h2><h3>{{ stu.friend.name }}</h3><hr /><h2>{{ hello }}</h2><hr /><MyButton></MyButton><MyButton></MyButton><MyButton></MyButton><MyButton></MyButton>
</template>
methods
- methods 用来指定实例对象中的方法
- 它是一个对象,可以在它里边定义多个方法
- 这些方法最终将会被挂载到组件实例上
- 可以直接通过组件实例来调用这些方法
- 所有组件实例上的属性都可以在模板中直接访问
- methods中函数的this会被自动绑定为组件实例
<script>
import MyButton from "./components/MyButton.vue"
import { shallowReactive } from "vue"export default {// data用来指定实例对象中的响应式属性data() {return {msg: "今天天气真不错!"}},/* methods 用来指定实例对象中的方法 - 它是一个对象,可以在它里边定义多个方法- 这些方法最终将会被挂载到组件实例上- 可以直接通过组件实例来调用这些方法 - 所有组件实例上的属性都可以在模板中直接访问- methods中函数的this会被自动绑定为组件实例*/methods: {sum(a, b){// console.log(this) // 组件实例 vmreturn a + b},changeMsg(){this.msg = "新的消息!"}}
}
</script>
<template><h1>{{ msg }}</h1><h2>{{ sum(2, 5) }}</h2><button @click="changeMsg">点我一下</button>
</template>
computed
- 计算属性,只在其依赖的数据发生变化时才会重新执行
- 对比:methods中的方法每次组件重新渲染都会调用
- 会对数据进行缓存
- 会被挂载到组件实例上
- 在计算属性的getter中,尽量只做读取相关的逻辑。 不要执行那些会产生(副)作用的代码,即不修改
- 计算属性的简写(只有getter时)
name(){return this.lastName + this.firstName}
- 可以为计算属性设置setter,使得计算属性可写,但是不建议这么做
<script>
import MyButton from "./components/MyButton.vue"
import { shallowReactive } from "vue"export default {// data用来指定实例对象中的响应式属性data() {return {msg: "今天天气真不错",stu: {name: "孙悟空",age: 18,gender: "男"},firstName: "悟空",lastName: "孙",}},methods: {updateAge() {if (this.stu.age === 18) {this.stu.age = 17} else {this.stu.age = 18}},// methods中的方法每次组件重新渲染都会调用getInfo() {console.log("getInfo调用了!")return this.stu.age >= 18? "你是一个成年人。": "你是一个未成年人。"}},/* computed 用来指定计算属性{属性名:getter}- 计算属性,只在其依赖的数据发生变化时才会重新执行- 会对数据进行缓存- 会被挂载到组件实例上*/computed: {info() {// 在计算属性的getter中,尽量只做读取相关的逻辑// 不要执行那些会产生(副)作用的代码,即不修改console.log("---> , info调用了!")return this.stu.age >= 18? "你是一个成年人!!!": "你是一个未成年人!!!"},// 计算属性的简写(只有getter时)// name(){// return this.lastName + this.firstName// }// 可以为计算属性设置setter,使得计算属性可写,但是不建议这么做name: {get() {return this.lastName + this.firstName},set(value) {// set在计算属性被修改时调用this.lastName = value[0]this.firstName = value.slice(1)}}}
}
</script>
<template><p>{{ msg }}</p><h1>{{ stu.name }} -- {{ stu.age }} -- {{ stu.gender }}</h1><h2>评语:{{ info }}</h2><h2>methods:{{ getInfo() }}</h2> <!--与上边info的效果一样,区别在于computed不会每次都调用,也不需要加括号--><button @click="updateAge">减龄</button><hr /><!-- <h3>{{ info }}</h3> --><h3>{{ name }}</h3><hr /><h2>{{ arr[0] }} -- {{ arr[1] }} -- {{ arr[2] }}</h2>
</template>