文章目录
项目安装
webpack方式
cnpm install -g @vue/cli
1.vue create 项目名 // 项目名不能有大写字母
2. 选择ts及vue3即可 // 选择ts就会加入ts
vite方式
全局安装 Vite
npm install -g create-vite-app
使用 Vite 创建 Vue3 项目
create-vite-app vue3-vite
Treeshaking特性
Tree shaking 是一种通过清除多余代码方式来优化项目打包体积的技术,专业术语叫 Dead code elimination
简单来讲,就是在保持代码运行结果不变的前提下,去除无用的代码。
Tree shaking是基于ES6模板语法(import与exports),主要是借助ES6模块的静态编译思想,在编译时就能确定模块的依赖关系,以及输入和输出的变量
Tree shaking无非就是做了两件事:
编译阶段利用ES6 Module判断哪些模块已经加载
判断那些模块和变量未被使用或者引用,进而删除对应代码
语法
setup
setup执行的时机
在beforeCreate之前执行(一次), 此时组件对象还没有创建
this是undefined, 不能通过this来访问data/computed/methods / props
其实所有的composition API相关回调函数中也都不可以
setup的参数
setup(props, context) / setup(props, {attrs, slots, emit})
props: 包含props配置声明且传入了的所有属性的对象 // 父子传值
attrs: 包含没有在props配置中声明的属性的对象, 相当于 this.
a
t
t
r
s
/
/
父
子
传
值
s
l
o
t
s
:
包
含
所
有
传
入
的
插
槽
内
容
的
对
象
,
相
当
于
t
h
i
s
.
attrs // 父子传值 slots: 包含所有传入的插槽内容的对象, 相当于 this.
attrs//父子传值slots:包含所有传入的插槽内容的对象,相当于this.slots // 插槽
emit: 用来分发自定义事件的函数, 相当于 this.$emit // 子传父的emit方法
ref
用法一 响应式数据
js 里需要.value
监听简单的数据(也可以监听复杂的对象,最终也会转为Proxy),进行响应式
setup(){
const num=ref(0)
function addNum() {
num.value++
}
return {
num,
addNum
}
}
获取节点
<template>
<div ref="myRef">获取单个DOM元素</div>
</template>
<script>
import { ref, onMounted } from 'vue';
export default {
setup() {
const myRef = ref(null);
onMounted(() => {
console.dir(myRef.value);
});
return {
myRef
};
}
};
</script>
**// 或者**
<input type="text" ref="inputRef">
setup() {
const inputRef = ref<HTMLElement|null>(null)
onMounted(() => { // 自动获取焦点
inputRef.value && inputRef.value.focus()
})
return {
inputRef
}
},
ts下的处理
const inputRef = ref<HTMLInputElement | null>(null);
const getInputRef = () => {
console.log((inputRef.value as HTMLInputElement).value);
};
v-bind() 注入方式
const color = ref("red");
<style lang='less' scoped>
h1 {
// 这种注入的方式只能使用ref
color: v-bind(color);
background-color: v-bind(bckColor);
}
</style>
toRefs
用于将reactive中的数据展开为响应式数据,可以直接在模板中访问使用
const userdata=reactive({
username:"小明"
})
return {
...toRefs(userdata)
};
// 使用
<p>
{{username}}
</p>
toRef
可以使用reactive包裹的部分数据
const userdata = reactive({
username: "小明",
age:18
});
const refname=toRef(userdata,"username")
return {
refname
};
<p>
ref----{{refname}}
</p>
isRef
用于判断值是不是ref
reactive
监听复杂的对象,可以深度监听
setup() {
// reactive 实现了深度监听
const user: any= reactive({
username: "小明",
age: 18,
likes: ["item-0", "item-1"],
});
function changeUserdata() {
user.username="小红",
user.likes[0]="见哈哈哈",
user.sex="男"
}
return {
user,
changeUserdata
};
},
hooks
在src下新建hooks文件夹,useUser.js文件(文件建立在哪都不重要,主要是函数式分离业务)
import {ref,reactive} from "vue"
function useUser(){
const inputEle=ref("")
const userdata = reactive({
username: "小白",
age: "18",
})
const getInputVal=()=>{
console.log(inputEle.value.value)
}
return {
userdata,
inputEle,
getInputVal
}
}
export default useUser
在需要的组件导入使用
import useUser from "@/hook/useUser.js";
import { toRefs } from 'vue';
export default {
setup() {
const { userdata, inputEle, getInputVal } = useUser();
return {
...toRefs(userdata),
inputEle,
getInputVal,
};
},
};
setup参数
provide/inject
深度传参
外层组件:
setup() {
const childdata = ref("默认数据");
const userdata=reactive({
username:"李白白",
age:18
})
// 定义一个修改provide数据的函数
const updataUser=(val)=>{
userdata.username=val
}
provide("userdata",userdata)
provide("updataUser",updataUser) // 将方法传递给组件
// 子组件
const userdata1=inject("userdata")
const updataUser=inject("updataUser")
<button @click="updataUser('杜甫')">在子组件修改provide数据</button>
父子组件的传值(同v2)
1.可以使用v2的
2.使用v3的setup参数来修饰
props: ["msg"], // 必须要先接收一下
setup(props) {
const { userdata, inputEle, getInputVal } = useUser();
const f_str = ref(props.msg + "-------子组件添加的数据"); // 可以对父组件传递过来的数据进行修饰
return {
...toRefs(userdata),
f_str,
inputEle,
getInputVal,
};
},
子传父
setup(props, context) {
const { userdata, inputEle, getInputVal } = useUser();
const f_str = ref(props.msg + "-------子组件添加的数据"); // 可以对父组件传递过来的数据进行修饰
const childdata = ref("");
const handleF = () => {
context.emit("getChilddata",childdata.value)
};
return {
...toRefs(userdata),
childdata,
f_str,
inputEle,
getInputVal,
handleF,
};
},
4.v-for(同v2)
computed计算属性
// 计算属性计算出的全部姓名
const fullname = computed({
get() {
return user.firstname + "_" + user.lastname;
},
set(val: string) {
const valarr = val.split("_");
user.firstname = valarr[0];
user.lastname = valarr[1];
},
});
// 如果不对新的值修饰,可以采用下面的写法
const newCount = computed(() => {
return "新的count" + count1.value;
});
watch 监听
watch(
user, // ref
() => {
fullname1.value = user.firstname + "---" + user.lastname;
},
{ immediate: true }
);
watch(
() => {
// ref对象可以直接使用值,reactive的对象,需要写成函数形式
return userdata.username;
},
() => {
console.log("userdata.username发生了改变");
},
{ immediate: true } // 表示一开始就会执行上面的监听
);
// watch 的第二种用法,自带第一次的显示
// watch监听获取到的全部姓名
watchEffect(() => {
fullname1.value = user.firstname + "---" + user.lastname;
});
监听多个
就需要以数组的形式监听,watchEffect不能监听
watch([
()=>state.name1
,
()=>state.name2
,
],([new1,new2],[old1,old2])=>{
console.log("new1",new1)
console.log("old1",old1)
console.log("new2",new2)
console.log("old2",old2)
})
生命周期
与 2.x 版本生命周期相对应的组合式 API
beforeCreate -> 使用 setup()
created -> 使用 setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed -> onUnmounted
errorCaptured -> onErrorCaptured
需要先从vue中导出才能使用 回调函数
onMounted(() => {
console.log(’–onMounted’)
})
路由周期 onBeforeRouteUpdate
// 切换路由时触发,第一次渲染不会触发
onBeforeRouteUpdate(async (val) => {
id.value = val.params.id; // 获取得到路由的参数 /:id
if (id.value >= 0 && id.value < 8) {
let data1 = await getBooks(
{
num: 1,
pageSize: 6,
},
id.value
);
data.booklist = data1.data;
}
});
路由
路由的基本结构
import { createRouter,createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about/:id',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
const router = createRouter({
// history: createWebHashHistory(), // hash模式,
history:createWebHistory(), // 模式可以直接修改,需要先导入
routes
})
export default router
函数式跳转
import { useRouter } from "vue-router"; // 导入
const router = useRouter(); // 不用return
const goAbout = () => {
router.push(`/about/123`)
};
动态路由参数获取
import {useRoute} from "vue-router" // 导入
const route=useRoute()
方式一
/:id 动态路由
route.params.id // 获取方式
方式二
router.push({path:”/home”,query:{name:’hhh’}}) // 形如 /home?name=’hhh’
route.query.name // 获取方式
路由的默认类名
在移动端做nav时使用
<nav class="nav">
<router-link to="/home">
首页
</router-link>
<router-link to="/Category">
分类
</router-link>
<router-link to="/shopCart">
购物车
</router-link>
<router-link to="/profile">
个人中心
</router-link>
</nav>
<style lang="scss">
a{
color: #444;
&.router-link-exact-active{
color: yellowgreen;
}
}
</style>