Vue UI组件库
移动端常用UI组件库
PC端常用UI组件库
ElementUI IView UI
element-ui基本使用
首先下载npm i element-ui (具体可以在官网的组件–快速上手中查看) main.js缺点,体积过大
import Vue from 'vue'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue'
Vue.config.productionTip = false
Vue.use(ElementUI);
const vm = new Vue({
el: '#app',
render: h => h(App),
})
按需引入 npm install babel-plugin-component -D 引入的时候,缺什么,就下载什么npm i xxx
babel.config.js
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset',
["@babel/preset-env", { "modules": false }]
],
plugins: [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
main.js
import Vue from 'vue'
import App from './App.vue'
import { Button, Row } from 'element-ui';
Vue.config.productionTip = false
Vue.component("el-button", Button);
Vue.component("el-row", Row);
const vm = new Vue({
el: '#app',
render: h => h(App),
})
App.vue
<template>
<div>
<button>原生的组件</button>
<el-row>
<el-button>默认按钮</el-button>
<el-button type="primary">主要按钮</el-button>
<el-button type="success">成功按钮</el-button>
<el-button type="info">信息按钮</el-button>
<el-button type="warning">警告按钮</el-button>
<el-button type="danger">危险按钮</el-button>
</el-row>
<el-row>
<el-button icon="el-icon-search" circle></el-button>
<el-button type="primary" icon="el-icon-edit" circle></el-button>
<el-button type="success" icon="el-icon-check" circle></el-button>
<el-button type="info" icon="el-icon-message" circle></el-button>
<el-button type="warning" icon="el-icon-star-off" circle></el-button>
<el-button type="danger" icon="el-icon-delete" circle></el-button>
</el-row>
</div>
</template>
<script>
export default {
name: "App",
};
</script>
Vue3快速上手
1.Vue3简介
- 2020年9月18日,Vue.js发布3.0版本,代号:One Piece(海贼王)
- 耗时2年多、2600+次提交、30+个RFC、600+次PR、99位贡献者
- github上的tags地址:https://github.com/vuejs/vue-next/releases/tag/v3.0.0
2.Vue3带来了什么
1.性能的提升
-
打包大小减少41% -
初次渲染快55%, 更新渲染快133% -
内存减少54%
2.源码的升级
3.拥抱TypeScript
4.新的特性
-
Composition API(组合API)
- setup配置
- ref与reactive
- watch与watchEffect
- provide与inject
- …
-
新的内置组件
-
其他改变
- 新的生命周期钩子
- data 选项应始终被声明为一个函数
- 移除keyCode支持作为 v-on 的修饰符
- …
一、创建Vue3.0工程
1.使用 vue-cli 创建
官方文档:https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-create
vue -V查看vue版本
vue --version
vue create vue3cli
cd vue3cli
npm run serve
2.使用 vite 创建
官方文档:https://v3.cn.vuejs.org/guide/installation.html#vite
vite官网:网址
- 什么是vite?—— 新一代前端构建工具。
- 优势如下:
- 开发环境中,无需打包操作,可快速的冷启动。
- 轻量快速的热重载(HMR)。
- 真正的按需编译,不再等待整个应用编译完成。
- 传统构建 与 vite构建对比图
npm init vite-app <project-name>
cd <project-name>
npm install
npm run dev
首次介绍
main.js
import { createApp } from 'vue'
import App from './App.vue'
const app=createApp(App)
app.mount("#app")
vue.config.js
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
lintOnSave:false
})
下载Vue3开发展工具
链接: https://pan.baidu.com/s/1J_iT_uoNqBM2zQzwQxYgCw?pwd=8jwc 提取码: 8jwc 复制这段内容后打开百度网盘手机App,操作更方便哦
二、常用 Composition API
组合式API 官方文档 #region #endregion
setup
- 理解:Vue3.0中一个新的配置项,值为一个函数。
- setup是所有Composition API(组合API)“ 表演的舞台 ”。
- 组件中所用到的:数据、方法等等,均要配置在setup中。
- setup函数的两种返回值:
- 若返回一个对象,则对象中的属性、方法, 在模板中均可以直接使用。(重点关注!)
- 若返回一个渲染函数:则可以自定义渲染内容。(了解)
- 注意点:
- 尽量不要与Vue2.x配置混用
- Vue2.x配置(data、methos、computed…)中可以访问到setup中的属性、方法。
- 但在vue3的setup中不能访问到Vue2.x配置(data、methos、computed…)。
- 如果有重名, setup优先。
- setup不能是一个async函数,因为返回值不再是return的对象, 而是promise, 模板看不到return对象中的属性。(后期也可以返回一个Promise实例,但需要Suspense和异步组件的配合)
<template>
<div>
<h1>我是APP组件</h1>
<h2>姓名:{{ name }}</h2>
<h2>年龄:{{ age }}</h2>
<h2>性别:{{ sex }}</h2>
<button @click="sayHello">vue3配置---点我说话</button>
<button @click="sayWelcome">vue2配置--点我欢迎</button>
<br>
<br>
<button @click="test">测试在vue2 的配置中去读取vue3 的数据和方法</button>
<button @click="test2">测试在vue3 的配置中去读取vue2 的数据和方法</button>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
sex: "男",
};
},
methods: {
sayWelcome() {
alert("欢迎美女!");
},
test() {
console.log(this.sex);
console.log(this.name);
console.log(this.age);
console.log(this.sayHello);
},
},
setup() {
let name = "张三";
let age = 18;
function sayHello() {
alert(`我叫${name},我${age}岁了,你好啊!`);
}
function test2() {
console.log(name);
console.log(age);
console.log(this.sex);
console.log(this.sayWelcome);
}
return {
name,
age,
sayHello,
test2
};
},
};
</script>
2.ref函数
- 作用: 定义一个响应式的数据
- 语法:
const/let xxx = ref(initValue) const定义的对象是可以修改里面的属性的,比如,const obj={}, obj.a=1允许,但是不允许obj={},不允许等于一个新对象
- 创建一个包含响应式数据的引用对象(reference对象,简称ref对象)。
- JS中操作数据:
xxx.value - 模板中读取数据: 不需要.value,直接:
<div>{{xxx}}</div> - 备注:
- 接收的数据可以是:基本类型、也可以是对象类型。
- 基本类型的数据:响应式依然是靠
Object.defineProperty() 的get 与set 完成的。 - 对象类型的数据:内部 “ 求助 ” 了Vue3.0中的一个新函数——
reactive 函数。
<template>
<div>
<h1>我是APP组件</h1>
<h2>姓名:{{ name }}</h2>
<h2>年龄:{{ age }}</h2>
<button @click="changeInfo">修改人的信息</button>
<h3>工作种类:{{job.type}}</h3>
<h3>工作薪水:{{job.salary}}</h3>
</div>
</template>
<script>
import { ref } from "vue";
export default {
name: "App",
setup() {
let name = ref("张三");
let age = ref(18);
let job = ref({
type: "前端工程师",
salary: "30k",
})
function changeInfo() {
name.value = "liuyue";
age.value = 20;
job.value.type="前端";
console.log(job);
}
return {
name,
age,
changeInfo,
job,
};
},
};
</script>
3.reactive函数
- 作用: 定义一个对象类型的响应式数据(基本类型不要用它,要用
ref 函数) - 语法:
const 代理对象= reactive(源对象) 接收一个对象(或数组),返回一个代理对象(Proxy的实例对象,简称proxy对象) - reactive定义的响应式数据是“深层次的”。
- 内部基于 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据进行操作。
4.Vue3.0中的响应式原理
vue2.x的响应式
-
实现原理:
-
对象类型:通过Object.defineProperty() 对属性的读取、修改进行拦截(数据劫持)。 -
数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)。 Object.defineProperty(data, 'count', {
get () {},
set () {}
})
-
存在问题:
- 新增属性、删除属性, 界面不会更新。
- 直接通过下标修改数组, 界面不会自动更新。
- 数据改了,但是vue2没有监测到
this.$set this.$delete
Vue3.0的响应式
- 实现原理:
- 通过Proxy(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。
- 通过Reflect(反射): 对源对象的属性进行操作。
- MDN文档中描述的Proxy与Reflect:
-
Proxy:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy -
Reflect:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect new Proxy(data, {
get (target, prop) {
return Reflect.get(target, prop)
},
set (target, prop, value) {
return Reflect.set(target, prop, value)
},
deleteProperty (target, prop) {
return Reflect.deleteProperty(target, prop)
}
})
proxy.name = 'tom'
新建一个html文件,在网页中修改删除都可以
<!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>
<script type="text/javascript">
let person={
name:'张三',
age:18
}
const p=new Proxy(person,{
get(target,propName){
console.log(`有人读取了p身上的${propName}属性`);
return Reflect.get(target,propName)
},
set(target,propName,value){
console.log(`有人修改了p身上的${propName}属性,我要去更新界面了`);
Reflect.set(target,propName,value)
},
deleteProperty(target,propName){
console.log(`有人删除了p身上的${propName}属性`);
return Reflect.deleteProperty(target,propName)
}
})
</script>
</body>
</html>
5.reactive对比ref
- 从定义数据角度对比:
- ref用来定义:基本类型数据。
- reactive用来定义:对象(或数组)类型数据。
- 备注:ref也可以用来定义对象(或数组)类型数据, 它内部会自动通过
reactive 转为代理对象。 - 从原理角度对比:
- ref通过
Object.defineProperty() 的get 与set 来实现响应式(数据劫持)。 - reactive通过使用Proxy来实现响应式(数据劫持), 并通过Reflect操作源对象内部的数据。
- 从使用角度对比:
- ref定义的数据:操作数据需要
.value ,读取数据时模板中直接读取不需要.value 。 - reactive定义的数据:操作数据与读取数据:均不需要
.value 。
6.setup的两个注意点
App.vue
<template>
<div>
<demo @hello="showHello" msg="你好啊" school="qut" >
<template v-slot:qwe>
<span>qut</span>
</template>
</demo>
</div>
</template>
<script>
import { ref, reactive } from "vue";
import demo from "./components/demo.vue";
export default {
name: "App",
components: { demo },
setup() {
function showHello(value) {
alert(`你触发了hello事件,我收到的参数是${value}!`);
}
return {
showHello,
};
},
};
</script>
demo.vue
<template>
<h2>姓名 {{ person.name }}</h2>
<h2>年龄{{ person.age }}</h2>
<button @click="test">测试触发一下demo组件的hello事件</button>
</template>
<script>
import { reactive } from "vue";
export default {
name: "demo",
props: ["msg", "school"],
emits: ["hello"],
setup(props, context) {
console.log("---setup----",context);
console.log("---setup----",context.slots);
let person = reactive({
name: "zhangsan",
age: 18,
});
function test() {
context.emit("hello", 666);
}
return {
person,
test,
};
},
};
</script>
<style>
</style>
7.计算属性与监视
1.computed函数
<template>
<h2>姓:</h2>
<input type="text" v-model="person.firstName" />
<h2>名:</h2>
<input type="text" v-model="person.lastName" /> <br /><br />
<span>全名:{{ person.fullname }}</span>
<input type="text" v-model="person.fullname" />
</template>
<script>
import { computed, reactive } from "vue";
export default {
name: "demo",
setup() {
let person = reactive({
firstName: "zhang",
lastName: "san",
});
person.fullname = computed({
get() {
return person.firstName + "-" + person.lastName;
},
set(value) {
const nameArr = value.split("-");
person.firstName = nameArr[0];
person.lastName = nameArr[1];
},
});
return {
person,
};
},
};
</script>
<style>
</style>
2.watch函数
-
与Vue2.x中watch配置功能一致 -
两个小“坑”:
- 监视reactive定义的响应式数据时:oldValue无法正确获取、强制开启了深度监视(deep配置失效)。
- 监视reactive定义的响应式数据中某个属性时:deep配置有效。
<template>
<h2>当前求和为:{{ sum }}</h2>
<button @click="sum++">点我加1</button>
<hr />
<h2>当前的信息是:{{ msg }}</h2>
<button @click="msg += '赵哲'">修改信息</button>
<hr />
<h2>当前的姓名是:{{ person.name }}</h2>
<h2>当前的年龄是:{{ person.age }}</h2>
<h2>当前的薪水是:{{ person.job.j1.salary }}k</h2>
<button @click="person.name += '~'">更改姓名</button>
<button @click="person.age++">更改年龄</button>
<button @click="person.job.j1.salary++">涨薪</button>
</template>
<script>
import { ref,reactive, watch } from "vue";
export default {
name: "demo",
setup() {
let sum = ref(0);
let msg = ref('你好啊,')
let person=reactive({
name:"张三",
age:18,
job:{
j1:{salary:20}
}
})
watch(sum, (newValue, oldValue) => {
console.log("sum变了", newValue, oldValue);
},{immediate:true});
watch([sum,msg], (newValue, oldValue) => {
console.log("sum或者msg变了", newValue, oldValue);
},{immediate:true});
watch(person,(newValue, oldValue) => {
console.log("person被修改了",newValue, oldValue);
},{immediate:true,deep:false}),
watch(()=>person.age,(newValue, oldValue)=>{
console.log("person中的age发生变化了",newValue, oldValue);
})
watch([()=>person.age,()=>person.name],(newValue, oldValue)=>{
console.log("person中的age/name发生变化了",newValue, oldValue);
})
watch(()=>person.job,(newValue, oldValue)=>{
console.log("person中的job发生变化了",newValue, oldValue);
},{deep:true})
return {
sum,
msg,
person,
};
},
};
</script>
3.watchEffect函数
- watchEffect有点像computed:
- 但computed注重的计算出来的值(回调函数的返回值),所以必须要写返回值。
- 而watchEffect更注重的是过程(回调函数的函数体),所以不用写返回值。
8.生命周期
vue2.x的生命周期
vue3.0的生命周期
1
<template>
<div>
<button @click="isShowDemo=!isShowDemo">切换隐藏/显示</button>
<demo v-if="isShowDemo"/>
</div>
</template>
<script>
import { ref } from "vue";
import demo from "./components/demo.vue";
export default {
name: "App",
components: { demo },
setup(){
let isShowDemo=ref(true)
return {
isShowDemo,
}
},
};
</script>
demo.vue(在components文件夹中)
<template>
<h2>当前求和为:{{ sum }}</h2>
<button @click="sum++">点我加1</button>
<hr />
</template>
<script>
import { ref,onBeforeMount,onMounted } from "vue";
export default {
name: "demo",
setup() {
let sum = ref(0);
onMounted(()=>{
console.log("---onMounted---");
})
return {
sum,
};
},
};
</script>
9.自定义hook函数
App.vue使用上面的 Demo.vue
<template>
<h2>当前求和为:{{ sum }}</h2>
<button @click="sum++">点我加1</button>
<hr />
<h2>当前点击鼠标坐标:x:{{ pointer.x }},y:{{ pointer.y }}</h2>
</template>
<script>
import { ref} from "vue";
import usePoint from "../hooks/usePoint"
export default {
name: "demo",
setup() {
let sum = ref(0);
//调用函数
let pointer=usePoint()
return {
sum,
pointer
};
},
};
</script>
<style>
</style>
usePoint.js(新建hooks文件夹)
import { onMounted, onBeforeUnmount, reactive } from "vue";
export default function (){
let pointer = reactive({
x: 0,
y: 0,
});
function savePointer(event) {
pointer.x = event.pageX;
pointer.y = event.pageY;
console.log(event.pageX, event.pageY);
}
onMounted(() => {
window.addEventListener("click",savePointer );
onBeforeUnmount(() => {
window.removeEventListener("click", savePointer);
});
});
return pointer
}
10.toRef
把…变成ref
-
作用:创建一个 ref 对象,其value值指向另一个对象(person)中的某个属性。(把属性拆散了使用) -
语法:const name = toRef(person,'name') -
应用: 要将响应式对象中的某个属性单独提供给外部使用时。 -
扩展:toRefs 与toRef 功能一致,但可以批量创建多个 ref 对象,语法:toRefs(person) App.vue
<template>
<div>
<button @click="isShowDemo=!isShowDemo">切换隐藏/显示</button>
<demo v-if="isShowDemo"/>
</div>
</template>
<script>
import { ref } from "vue";
import demo from "./components/demo.vue";
export default {
name: "App",
components: { demo },
setup(){
let isShowDemo=ref(true)
return {
isShowDemo,
}
},
};
</script>
demo.vue
<template>
<!-- 通过输出判断,修改的是不是person中的属性 -->
<h2>总体:{{person}}</h2>
<h2>当前的姓名是:{{ name }}</h2>
<h2>当前的年龄是:{{ age }}</h2>
<h2>当前的薪水是:{{ salary }}k</h2>
<button @click="name += '~'">更改姓名</button>
<button @click="age++">更改年龄</button>
<button @click="salary++">涨薪</button>
</template>
<script>
import { ref, reactive, toRef, toRefs } from "vue";
export default {
name: "demo",
setup() {
let person = reactive({
name: "张三",
age: 18,
job: {
j1: { salary: 20 },
},
});
let x=toRefs(person)
console.log(x);
return {
person,
name: toRef(person, "name"),
age: toRef(person, "age"),
salary: toRef(person.job.j1, "salary"),
...toRefs(person)
};
},
};
</script>
三、其它 Composition API
1.shallowReactive 与 shallowRef
demo.vue
<template>
<h2>当前的x.y是:{{ x.y }}</h2>
<button @click="x.y++">更改X的值</button>
<h2>总体:{{ person }}</h2>
<h2>当前的姓名是:{{ name }}</h2>
<h2>当前的年龄是:{{ age }}</h2>
<h2>当前的薪水是:{{ job.j1.salary }}k</h2>
<button @click="name += '~'">更改姓名</button>
<button @click="age++">更改年龄</button>
<button @click="job.j1.salary++">涨薪</button>
</template>
<script>
import { ref, reactive, toRef, toRefs, shallowReactive, shallowRef } from "vue";
export default {
name: "demo",
setup() {
let person = reactive({
name: "张三",
age: 18,
job: {
j1: { salary: 20 },
},
});
let x = ref({
y: 0,
});
return {
x,
person,
...toRefs(person),
};
},
};
</script>
2.readonly 与 shallowReadonly
- readonly: 让一个响应式数据变为只读的(深只读)。
- shallowReadonly:让一个响应式数据变为只读的(浅只读)。
- 应用场景: 不希望数据被修改时。
<template>
<h2>当前求和是:{{sum }}</h2>
<button @click="sum++">更改X的值</button>
<h2>总体:{{ person }}</h2>
<h2>当前的姓名是:{{ name }}</h2>
<h2>当前的年龄是:{{ age }}</h2>
<h2>当前的薪水是:{{ job.j1.salary }}k</h2>
<button @click="name += '~'">更改姓名</button>
<button @click="age++">更改年龄</button>
<button @click="job.j1.salary++">涨薪</button>
</template>
<script>
import { ref, reactive, toRef, toRefs, shallowReactive, shallowRef, readonly, shallowReadonly } from "vue";
export default {
name: "demo",
setup() {
let person = reactive({
name: "张三",
age: 18,
job: {
j1: { salary: 20 },
},
});
let sum = ref(0)
sum=readonly(sum)
person=shallowReadonly(person)
return {
sum,
person,
...toRefs(person),
};
},
};
</script>
3.toRaw 与 markRaw
- toRaw:
- 作用:将一个由
reactive 生成的响应式对象转为普通对象,ref创作的不行。 - 使用场景:用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面更新。
- markRaw:
- 作用:标记一个对象,使其永远不会再成为响应式对象。
- 应用场景:
- 有些值不应被设置为响应式的,例如复杂的第三方类库等。
- 当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能。
demo.vue
<template>
<h2>当前求和是:{{ sum }}</h2>
<button @click="sum++">更改X的值</button>
<h2>总体:{{ person }}</h2>
<h2>当前的姓名是:{{ name }}</h2>
<h2>当前的年龄是:{{ age }}</h2>
<h2>当前的薪水是:{{ job.j1.salary }}k</h2>
<button @click="name += '~'">更改姓名</button>
<button @click="age++">更改年龄</button>
<button @click="job.j1.salary++">涨薪</button>
<button @click="showRawPerson">输出最原始的person</button>
<hr />
<button @click="addCar">给一个人添加车</button>
<h2 v-show="person.car">座驾信息:{{ person.car }}</h2>
<button v-show="person.car" @click="person.car.name += '?'">换车名</button>
<!-- 有车才显示这两个按钮 -->
<button v-show="person.car" @click="person.car.price++">换价格</button>
</template>
<script>
import { ref, reactive, toRefs, toRaw, markRaw } from "vue";
export default {
name: "demo",
setup() {
let sum = ref(0);
let person = reactive({
name: "张三",
age: 18,
job: {
j1: { salary: 20 },
},
});
function showRawPerson() {
const p = toRaw(person);
p.age++;
console.log(p);
}
function addCar() {
let car = { name: "奔驰", price: "40" };
person.car = car;
console.log(person);
}
return {
sum,
person,
...toRefs(person),
showRawPerson,
addCar,
};
},
};
</script>
4.customRef
ref(精装房)customRef(毛坯房) 想要实现,上面的输入框输入的文字发生变化时,下面的输入框间隔一段时间后发生响应的变化
<template>
<div>
<!-- 上面输入框输入,下面等一秒钟在输入 -->
<input type="text" v-model="keyWord" />
<h3>{{ keyWord }}</h3>
</div>
</template>
<script>
import { ref, customRef } from "vue";
import demo from "./components/demo.vue";
export default {
name: "App",
components: { demo },
setup() {
function myRef(value, delay) {
let timer;
return customRef((track, tragger) => {
return {
get() {
console.log(`有人从myRef中读取数据了,我把${value}给她了`);
track();
return value;
},
set(newValue) {
console.log(`有人把myRef中数据更改了:${newValue}`);
clearTimeout(timer);
timer = setTimeout(() => {
value = newValue;
tragger();
}, delay);
},
};
});
}
let keyWord = myRef("hello",1000);
return {
keyWord,
};
},
};
</script>
5.provide 与 inject
父子之间一般不用
-
具体写法:
-
祖组件中: setup(){
......
let car = reactive({name:'奔驰',price:'40万'})
provide('car',car)
......
}
-
后代组件中: setup(props,context){
......
const car = inject('car')
return {car}
......
}
App.vue
<template>
<div class="app">
<h3>我是APP组件(祖先){{name}}---{{price}}</h3>
<Child/>
</div>
</template>
<script>
import { reactive,toRefs,provide } from 'vue'
import Child from './components/Child.vue'
export default {
name:"App",
components:{
Child,
},
setup(){
let car=reactive({
name:"奔驰",
price:"40"
});
provide('car',car);
return{...toRefs(car)}
}
}
</script>
<style>
.app{
background-color: aqua;
}
</style>
其实没啥用,但是不写的话,就没办法生成孙组件 Child.vue
<template>
<div class="child">
<h3>我是Child组件(子组件)</h3>
<Son/>
</div>
</template>
<script>
import Son from "../components/Son.vue"
export default {
name:"Child",
components:{
Son,
}
}
</script>
<style>
.child{
background-color: rgb(236, 122, 122);
}
</style>
son.vue
<template>
<div class="son">
<h3>我是Son组件(孙){{car.name}}-----{{car.price}}</h3>
</div>
</template>
<script>
import {inject} from'vue'
export default {
name:"Son",
setup(){
let car=inject('car')
return{car}
}
}
</script>
<style>
.son{
background-color: rgb(233, 111, 70);
}
</style>
6.响应式数据的判断
- isRef: 检查一个值是否为一个 ref 对象
- isReactive: 检查一个对象是否是由
reactive 创建的响应式代理 - isReadonly: 检查一个对象是否是由
readonly 创建的只读代理 - isProxy: 检查一个对象是否是由
reactive 或者 readonly 方法创建的代理 只需APP.vue
<template>
<div class="app">
<h3>我是APP组件{{ name }}---{{ price }}</h3>
</div>
</template>
<script>
import {
reactive,
toRefs,
ref,
readonly,
isRef,
isReactive,
isReadonly,
isProxy,
} from "vue";
export default {
name: "App",
setup() {
let car = reactive({
name: "奔驰",
price: "40",
});
let sum = ref(0);
let car2 = readonly(car);
console.log(isRef(sum));
console.log(isReactive(car));
console.log(isReadonly(car2));
console.log(isProxy(car));
console.log(isProxy(car2));
console.log(isProxy(sum));
return { ...toRefs(car) };
},
};
</script>
<style>
.app {
background-color: aqua;
}
</style>
四、Composition API 的优势
1.Options API 存在的问题
使用传统OptionsAPI中,新增或者修改一个需求,就需要分别在data,methods,computed里修改 。
2.Composition API 的优势
我们可以更加优雅的组织我们的代码,函数。让相关功能的代码更加有序的组织在一起。
五、新的组件
1.Fragment
- 在Vue2中: 组件必须有一个根标签
- 在Vue3中: 组件可以没有根标签, 内部会将多个标签包含在一个Fragment虚拟元素中
- 好处: 减少标签层级, 减小内存占用
2.Teleport
- 什么是Teleport?——
Teleport 是一种能够将我们的组件html结构移动到指定位置的技术。 使用provide目录中的APP和Child son.vue
<template>
<div class="son">
<h3>我是Son组件(孙)</h3>
<Dialog/>
</div>
</template>
<script>
import Dialog from './Dialog.vue'
export default {
name:"Son",
components:{
Dialog,
}
}
</script>
<style>
.son{
background-color: rgb(233, 111, 70);
}
</style>
Dialog.vue
<template>
<div>
<button @click="isShow=true">点我弹个窗</button>
<teleport to="body"> <!-- 在elements控制台可以发现,这个元素是被添加到了和app平级 -->
<div v-if="isShow" class="mask">
<div class="dialog">
<h3>我是一个弹窗</h3>
<h4>一些内容</h4>
<h4>一些内容</h4>
<h4>一些内容</h4>
<h4>一些内容</h4>
<button @click="isShow=false">关闭弹窗</button>
</div>
</div>
</teleport>
</div>
</template>
<script>
import {ref} from "vue"
export default {
name:"Dialog",
setup(){
let isShow=ref(false)
return{
isShow,
}
}
}
</script>
<style>
.mask{
position: absolute;
top:0;
bottom:0;
left:0;
right:0;
background-color: rgba(0, 0, 0, 0.5);
}
.dialog{
text-align: center;
position: absolute;
top:50%;
left:50%;
transform: translate(-50%,-50%);
background-color: rgb(221, 196, 85);
width: 400px;
}
</style>
3.Suspense
App.vue
<template>
<div class="app">
<h3>我是APP组件</h3>
<Suspense>
<template v-slot:default>
<Child />
</template>
<template v-slot:fallback>
<!-- 还未加载出来的时候闪现的 -->
<h3>稍等,加载中...</h3>
</template>
</Suspense>
</div>
</template>
<script>
import { reactive } from "vue";
import {defineAsyncComponent} from 'vue'
const Child=defineAsyncComponent(()=>{
return import('./components/Child.vue')
})
export default {
name: "App",
components:{Child}
};
</script>
<style>
.app {
background-color: aqua;
}
</style>
Child.vue
<template>
<div class="child">
<h3>我是Child组件(子组件)</h3>
{{ sum }}
</div>
</template>
<script>
import { ref } from "vue";
export default {
name: "Child",
async setup() {
let sum = ref(0);
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ sum });
}, 1000);
});
return await p;
},
};
</script>
<style>
.child {
background-color: rgb(236, 122, 122);
}
</style>
六、其他
1.全局API的转移
-
Vue 2.x 有许多全局 API 和配置。
-
例如:注册全局组件、注册全局指令等。
Vue.component('MyButton', {
data: () => ({
count: 0
}),
template: '<button @click="count++">Clicked {{ count }} times.</button>'
})
Vue.directive('focus', {
inserted: el => el.focus()
}
-
Vue3.0中对这些API做出了调整:
2.其他改变
|