笔记:vue3+ts 组合式项目 (ts声明数据类型很明确:const常量、let变量 、 val有变量提升)
ts会导致无法访问其他浏览器api属性,需要自己引入或注释
先介绍ts :ts与js区别
基本数据类型不同
js: boolean类型、number类型、string类型、array类型、nudefined、null
ts: 除了上面的类型外,还包含tuple类型(元组类型)、enum类型(枚举类型)、any类型(任意类型)
js 动态类型,运行运行时明确变量的类型,变量的类型由变量的值决定,并跟随值的改变而改变;ts 静态类型,声明时确定类型,之后不允许修改
js 直接运行在浏览器和环境中;ts 编译运行,始终先编译成JavaScript在运行
js 弱类型,数据类型可以被忽略的语言。一个变量可以赋不同数据类型的值;ts 强类型,一旦一个变量被指定了某个数据类型,如果不经过强制转换,那么它就永远是这个数据类型了;
ts增加的语法:
(1)静态类型:有利于检查代码错误,运行前检查类型错误
(2)函数缺省参数值
(3)class类
(4)模块:可以把声明、数据、函数和类封装在模块中
(5)接口
(6)类型注解:通过类型注解来增加编译时静态类型检查
一、创建vue3
1、可以使用这命令行自定义创建
vue create 项目名称
2、根据vue3官网创建
npm init @vitejs/app 项目名
二、在 配置
import { createApp } from 'vue'
import App from './'
import router from './router'
import store from './store'
import Vant from 'vant';
import util from "./Util"
import axios from 'axios'
import request from "@/api/request"
import 'vant/lib/';
// createApp工厂函数然而,创建实例对象
//其实就相当于vue2中的vm,mount('#app')就相当于$mount('#app'),
//并且vue2的写法在vue3不能兼容
const app = createApp(App);
app.use(store);
app.use(Vant);
app.use(router);
// 挂载原型>>>注意这里必须要加$!!否则在组件中无法被访问到!访问也要在组件中使用this.$brower!
app.config.globalProperties.$axios = axios;
//组件使用1.????引入
//import {getCurrentInstance} from 'vue'
//const {proxy} = getCurrentInstance
// proxy.$({ name:'home'})
app.mount('#app');
// createApp(App).use(store).use(Vant).use(router).mount('#app')
三、
<template>
<!--vue3没有跟标签 -->
<router-view/>
</template>
四、使用
ref
第一种写法:
setup 函数是 Composition API(组合API)的入口
它比 beforeCreate
和 created
这两个生命周期还要快,就是说, setup
在beforeCreate,created
前,它里面的this打印出来是undefined;
setup
可以接受两个参数,第一个参数是props
,也就是组件传值,第二个参数是context
,上下文对象,context
里面还有三个很重要的东西attrs,slots,emit
,它们就相当于vue2里面的this.$attrs,this.$slots,this.$emit
。
<script>
import {ref} from 'vue' //响应式 ref需要 加value访问。
//ref把它们变成了对象 并且还是RefImpl的实例对象
export default {
name: 'App',
setup(){
let name = ref('王者')
let sex= ref('男')
//方法
function onclick(){
console.log(`我叫${name.value},性别:${sex}`)//我叫王者,性别:[object Object]
}
//返回一个对象
return {
name,
sex,
onclick
}
}
}
</script>
第二种写法 :不需要return
可以用vue3新语法糖<script setup>就相当于在编译运行是把代码放到了 setup 函数中运行,然后把导出的变量定义到上下文中,并包含在返回的对象中
插入子组件也不需要 components
reactive
reactive
只能定义对象类型的响应式数据,前面说到的ref
里是对象的话,会自动调用reactive
,把Object转换为Proxy
<template>
<div class="home">
<h1>姓名:{{name}}</h1>
<h1>年龄:{{age}}</h1>
<h2>职业:{{job.occupation}}<br>薪资:{{job.salary}}</h2>
<h3>爱好:{{hobby[0]}},{{hobby[1]}},{{ hobby[2] }}</h3>
<button @click="say">修改</button>
</div>
</template>
<script setup>
import {ref,reactive} from 'vue'
let name = ref('前端')
let age = ref(18)
let job=reactive({
occupation:'程序员',
salary:'10k'
})
let hobby=reactive(['刷剧','吃鸡','睡觉'])
console.log(name)
console.log(age)
//方法
function say(){
job.salary='12k'
hobby[0]='泡妞'
}
</script>
ref 与 reactive的区别
1、ref用来定义:基本类型数据。
2、ref通过()
的get与set来实现响应式(数据劫持)。
3、ref定义的数据:操作数据需要.value,读取数据时模板中直接读取不需要.value。
4、reactive用来定义:对象或数组类型数据。
5、reactive通过使用Proxy
来实现响应式(数据劫持), 并通过Reflect
操作源代码内部的数据。
6、reactive定义的数据:操作数据与读取数据:均不需要.value。
ref可以定义对象或数组的,它只是内部自动调用了reactive来转换。
vue3响应原理
通过Proxy
(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。
通过Reflect
(反射): 对源对象的属性进行操作。
computed
计算属性
<div>{{fullName}}</div>
//····过程就算了·····
import {ref,reactive,computed} from 'vue'
const age = ref(9)
let job=reactive({
occupation:'程序员',
salary:'10k',
age:13
})
//新常量获取计算结果
const fullName=computed(()=>{
return job.age+age.value
})
let names=reactive({
familyName:'阿',
lastName:'斌'
})
//属性修改
names.fullName=computed({
get(){
return names.familyName+'.'+names.lastName
},
set(value){
let nameList=value.split('.')
names.familyName=nameList[0]
names.lastName=nameList[1]
}
})
watch
监听器
用法:
let names=reactive({
familyName: '鳌',
age:23,
job:{
salary:10
}
})
//有Bug newValue,oldValue两参数没变化
// watch(names,(newValue,oldValue)=>{/
// (`names改变了`,newValue,oldValue)
// },{deep:false})
watch([()=>names.age,()=>names.familyName],(newValue,oldValue)=>{
console.log('names222改变了',newValue,oldValue)
})
watch(()=> names.job.salary,(newValue,oldValue)=>{
console.log('names3333改变了',newValue,oldValue)
})
defineExpose
重要
setup
相当于是一个闭包,除了内部的 template
模板,谁都不能访问内部的数据和方法。如果需要对外暴露 setup
中的数据和方法,需要使用 defineExpose
API。
父组件
<home msg="hello" @onclick="say" ref="ChangeCarrierRef"></home>
<span style="font-size: 0.3243rem;" ref="element" @click="childCtx">模拟首页</span>
import home from '@/components/'
import {defineExpose,ref} from 'vue'
let name = ref('流星')
let age = 18
//方法
function say(nul){
console.log(`我叫${name.value},今年${age}岁`,nul)
}
const ChangeCarrierRef = ref()
const element = ref()//根据ref获取元素
const childCtx = () => {
console.log('点',element.value);//获取元素
ChangeCarrierRef.value.ageInc(5)//触发子组件事件
}
defineExpose({
say,childCtx,
name
})
子组件
<template>
<div @click="ageInc(1)">测试我是子组件!{{name+age}}</div>
<div >测试{{ props.msg }}</div>
</template>
<script setup>
import { ref, defineProps, defineEmits,defineExpose } from 'vue';
const emit = defineEmits(['onclick'])
const props = defineProps({
msg: String
})
const name = ref('CoCoyY1')
let age = ref(18)
const ageInc = (nul) => {
age.value+=nul;
emit('onclick','传参')//触发父组件事件
}
defineExpose({ageInc})//共享
</script>
访问原型链的axios,router,
使用getCurrentInstance
import {getCurrentInstance,reactive} from 'vue'
const obj = reactive({
username:'',
password:''
})
// const router=useRouter()
const {proxy} = getCurrentInstance()
const onSubmit = (values) => {
console.log('submit', values);
proxy.$router.push({
name:'home'
})
};