vite版本创建方式:
npm init vite viteapp -- --template vue
main.js的样子:
一、setup
(1) setup() 函数:
- 语法:返回的对象的成员可以在模板中使用,也可以在组件的api中使用
但是在这个函数中不能使用组件api中的东西
-
作用:为hook提供开发场景
-
setup函数中可以声明一些变量/函数 然后返回出去 供组件使用
-
setup函数可以设计成 script标签中写这个同名单词的属性 然后使整个标签环境都为setup函数环境(脚手架实现的)
-
setup函数内部的变量可以去设计为响应式的变量 可以使用官方的hook即ref reactive等工具
-
- 特点:
-
这个函数内部的函数/变量是局部的
-
这个函数的返回值可以被当前组件的任意地方使用
-
这个函数内部不能使用this来操作组件数据
-
setup返回的对象中的数据和data中的数据同名了 setup的优先级更高
-
setup在组件加载期间,只会运行一次
-
-
示例:
<script>
export default {
setup(props) {
var a = "这是标题";
var b = [1, 2, 3];
function fn() {
console.log("fn");
}
var hookmsg = "hookmsg";
function changehookmsg() {
hookmsg = "修改了hookmsg";
console.log("修改了hookmsg,但是数据不改");
}
//return出来后才能供外部使用 使用打包工具就可以不用一个一个导出
return { title: "yoyo", b, fn,changehookmsg ,hookmsg};
}
};
</script>
<template>
<div>
<p>{{title}}</p>
<div v-for="(el, index) in b" :key="index">
<p>{{el}}</p>
</div>
<button @click="fn">fn</button>
<p>{{hookmsg}}--非响应式的</p>
<button @click="changehookmsg">changehookmsg</button>
</div>
</template>
- 结果显示:
(2) setup属性:(setup函数的语法糖)
setup属性:
- 会让打包工具打包时直接帮忙把setup函数内部声明的变量/函数 return 然后外部就可以使用了 不需要this
- 可以直接导入组件 直接使用 不用注册和懒加载...
- 示例:
<script setup>
var a = "yoyo";
var b = [1, 2, 3];
var msg="hello";
function fn() {
console.log("fn");
}
var hookmsg = "hookmsg";
function changehookmsg() {
hookmsg = "修改了hookmsg";
console.log("修改了hookmsg,但是数据不改");
}
function change() {
msg = "haha";
console.log("修改了msg,但是数据不改");
}
</script>
<template>
<div>
<p>{{msg}}</p>
<button @click="change">修改msg</button>
<p>{{a}}</p>
<div v-for="(el, index) in b" :key="index">
<p>{{el}}</p>
</div>
<button @click="fn">fn</button>
<p>{{hookmsg}}--非响应式的</p>
<button @click="changehookmsg">changehookmsg</button>
</div>
</template>
- 显示结果:
二、响应式API——ref函数
-
作用:定义一个响应式的数据,可根据需求灵活设计数据是否为响应式
让数据之间是独立的,只局部刷新绑定了ref的变量
-
语法:let xxx = ref("value")
-
创建一个包含响应式的数据的引用对象(reference对象)
-
js中操作数据:xxx.value="new_value"
-
模板中读取数据不需要.value,直接<div>{{xxx}}</div>
-
-
注意
-
接收的数据类型可以是基本数据类型也可以是引用数据类型
-
基本类型的数据:响应式依然是靠Object.defineProperty()的get和set完成的
-
对象类型的数据:内部“求助”了Vue3.0的一个新的函数------reactive函数
-
-
响应式设计:
就是监听了value的改变 劫持value属性的setter getter
因此ref一般用在基本数据,或者引用数据的嵌套层级不深的数据上
- 示例:
<script setup>
import {ref} from "vue"
//msg0为普通变量
let msg0="msg0--hello"
//msg为响应式的变量
let msg=ref("msg--hello")
let changeMSG0=()=>{
msg0.value="msg0改变了"
console.log(msg0.value)
}
let changeMSG=()=>{
msg.value="msg改变了"
console.log(msg.value)
}
</script>
<template>
<div>
<p>{{msg0}}</p>
<button @click="changeMSG0">修改msg0</button>
<p>{{msg}}</p>
<button @click="changeMSG">修改msg</button>
</div>
</template>
- 显示结果:
三、响应式API——reactive函数
-
作用:定义一个对象类型的响应式数据(基本数据类型用ref函数)
-
语法:const 代理一个对象 = reactive(被代理的对象) 接收一个对象(或数组),返回一个代理器对象(proxy对象)
-
js中操作数据:不需要.value 直接操作对象
-
-
注意:reactive定义的响应式数据是“深层次的”
-
响应式设计:
跟ref一样 但是底层基于ES6的Proxy实现,代理了整个引用数据
- 示例:
<script setup>
import { reactive } from "vue";
let arr = reactive([
{ name: "红烧肉", info: { price: 21, state: "可出餐" }, count: 5 },
{ name: "肉末茄子", info: { price: 18, state: "已售完" }, count: 0 },
{ name: "水煮肉片", info: { price: 40, state: "可出餐" }, count: 2 }]
);
let changearr = () => {
arr[1].info.state ="可出餐";
arr[1].count =1;
};
</script>
<template>
<div>
<div v-for="(item, index) in arr" :key="index">
<p>{{item}}</p>
</div>
<button @click="changearr">changearr</button>
</div>
</template>
- 显示结果:
四、Vue2.0和Vue3.0中的响应式原理
(1)vue2.0的响应式
-
实现原理
-
对象类型:通过Object.definedProperty()对属性的读取、修改进行拦截(数据劫持)
-
数组类型:通过重写更新数据的一系列方法来实现拦截。(对数组的方法进行了包裹)
存在问题:
-
新增属性,删除属性都不会刷新界面
-
直接通过下标修改数组,界面不会自动更新
-
(2)vue3.0的响应式
-
实现原理
-
通过Proxy(代理):拦截对象中任意属性的变化,包括:属性的读写,属性的添加,属性的删除等
-
通过Reflect(反射):对被代理对象的属性进行操作
-
MDN文档中描述的Proxy与Reflect:
-
Proxy:Proxy - JavaScript | MDN
-
Reflect:Reflect - JavaScript | MDN
-
-
五、计算属性
-
与vue2.x中computed配置功能一致
示例:
<script setup>
import { reactive, computed } from "vue";
let arr = reactive([
{ name: "红烧肉", info: { price: 21, state: "可出餐" }, count: 5 },
{ name: "肉末茄子", info: { price: 18, state: "已售完" }, count: 0 },
{ name: "水煮肉片", info: { price: 40, state: "可出餐" }, count: 2 }
]);
let total = computed(() => {
console.log("计算了1次总价");
return arr.reduce((n1, n2) => {
return n1 + n2.info.price * n2.count;
}, 0);
});
let changename = () => {
arr[0].name ="麻婆豆腐";
console.log("修改了菜名但没有修改价格和数量,不触发computed")
};
let changecount = () => {
arr[0].count =6;
console.log("修改了数量,触发了computed")
};
</script>
<template>
<div class="box">
<h3>Box1</h3>
<div v-for="(el, index) in arr" :key="index">
<div>
<button @click="changename">修改菜名</button>
{{el.name}}:{{el.info.price}}元
<span>数量:{{el.count}}</span>
<button @click="changecount">修改数量</button>
</div>
</div>
<p> 利润:<b>{{total}}元</b></p>
</div>
</template>
结果显示: