data(){
return {}
}
Vue.createApp()
<div id="counter">Counter: {{ counter }}div>
const Counter = {
data() {
return {
counter: 0,
};
},
};
Vue.createApp(Counter).mount("#counter");
createApp
函数创建一个新的应用实例开始的:const app = Vue.createApp({});
const app = Vue.createApp({});
app.component("SearchInput", SearchInputComponent); //注册全局组件
app.directive("focus", FocusDirective); //自定义指令
app.use(LocalePlugin); //引入插件
应用实例暴露的大多数方法都会返回该同一实例,允许链式:
Vue.createApp({})
.component("SearchInput", SearchInputComponent)
.directive("focus", FocusDirective)
.use(LocalePlugin);
app.unmount()
const app = Vue.createApp({
data() {
return {
title: "hello Vue3.",
};
},
beforeUnmount() {
console.log("beforeUnmount");
},
unmounted() {
console.log("unmounted");
},
});
app.mount("#root");
setTimeout(() => {
app.unmount(); // 销毁这个实例
}, 3000);
<script src="https://unpkg.com/[email protected]/lodash.min.js"></script>
<script>
Vue.createApp({
methods: {
// 用 Lodash 的防抖函数
click: _.debounce(function() {
// ... 响应点击 ...
}, 500)
}
}).mount('#app')
</script>
app.component("save-button", {
created() {
// 使用 Lodash 实现防抖
this.debouncedClick = _.debounce(this.click, 500);
},
unmounted() {
// 移除组件时,取消定时器
this.debouncedClick.cancel();
},
methods: {
click() {
// ... 响应点击 ...
},
},
template: `
`,
});
v-if
和 v-for
v-if
和 v-for
同时使用时,v-for
的权重高v-if
的权重更高,而且在 vue3 中 v-for
也不需要我们写 v-key
来使用了v-for
中使用的 ref
attribute 会用 ref 数组填充相应的 $refs
property。当存在嵌套的 v-for
时,这种行为会变得不明确且效率低下。$ref
数组。要从单个绑定获取多个 ref,请将 ref
绑定到一个更灵活的函数上 (这是一个新特性):
<button @click="one($event), two($event)">Submitbutton>
// ...
methods: {
one(event) {
// 第一个事件处理器逻辑...
},
two(event) {
// 第二个事件处理器逻辑...
}
}
在 vue2 中,可以通过 keyCode
来修改 v-on
的方法
使用键码
使用按键别名
也可使使用 config.keyCodes
,自定义自己的别名
Vue.config.keyCodes = {
f1: 112,
};
在 vue3 中 config.keyCodes被废弃
$attrs
包含class
&style
vue2 中,在子组件标签中的 class
不会出现在 ``
Vue3 中,$attrs
现在包含了所有传递给组件的 attribute,包括 class
和 style
。
inheritAttrs: false
是 falsed 的时候 ,子组件标签上的属性不会继承到子组件内部元素上,当是 true
的时候,会继承到子组件最外层元素上$attrs
中存在<div id="root">
<date-picker data-status="activated" class="a">date-picker>
div>
<script>
const app = Vue.createApp({
})
app.component('date-picker', {
inheritAttrs: false,
template: `
`,
created() {
// console.log(this.$attrs.class)
}
})
app.mount('#root')
</script>
事件名
<div id="root">
<parent-com @aaa="handleClick">parent-com>
div>
const app = Vue.createApp({
methods: {
handleClick() {
console.log("click.");
},
},
});
app.component("parent-com", {
emits: ["aaa"],
template: `
`,
});
app.mount("#root");
验证抛出的事件
$emit
调用的参数,并返回一个布尔值以指示事件是否有效。emits:{
aaa:(e)=>{
if(e>10){
return true
}else{
return false
}
}
},
v-model 参数
v-model
使用 modelValue
作为 prop 和 update:modelValue
作为事件。我们可以通过向 v-model
传递参数来修改这些名称:// 理解:s 将自定义事件 aaa 的返回值做了动态绑定
<div id="root">
{{ counted }}
<parent-com v-model:aaa="counted">parent-com>
div>
// props 中的 aaa 就是 每次从父组件传下来的值
// emits 使用 update:aaa 来定义事件
// this.emit 触发事件,返回值到父组件
<script>
const app = Vue.createApp({
data() {
return {
counted:1
}
}
});
app.component("parent-com", {
data(){
return{
bbb:1
}
},
props:['aaa'],
emits:['update:aaa'],
template: `
`,
methods:{
handleClick(){
this.bbb++
this.$emit('update:aaa',this.bbb)
}
}
});
app.mount("#root");
</script>
<todo-button> Add todo todo-button>
<button class="btn-primary">
<slot>slot>
button>
新增 v-slot
简写为 #
<div id="root">
// v-slot:名字=“传递参数”
<todo-list v-slot:list="{ index, item }">
<span>{{index}}span> -
<span>{{item}}span>
todo-list>
div>
const app = Vue.createApp({});
app.component("todo-list", {
data() {
return {
items: ["feed a cat", "Buy milk"],
};
},
// 渲染插槽,这里用的是具名插槽,name 绑定插槽,item,index用来传递参数
template: `
-
`,
});
app.mount("#root");
Vue3 的开发文档中将这个提出来放到了 深入组件 这一栏。
基础使用
在根组件中使用 Provide
来声明一个变量
provide: {
user: 'John Doe'
},
在需要用到改参数的子组件中使用inject
来获取
inject: ['user'],
处理响应式
使用 Vue3 ,存储在实例中的 computed
const { createApp, computed } = Vue
provide() {
return {
msg: Vue.computed(() => this.str)
}
},
获取的方法还是使用 inject
inject: ['msg'],
使用挂载在 vue 实例上的方法 defineAsyncComponent
,需要做异步的组件返回一个 promise 对象。
const { createApp, defineAsyncComponent } = Vue;
const app = createApp({});
const AsyncComp = defineAsyncComponent(
() =>
new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
template: "I am async!",
});
}, 3000);
})
);
app.component("async-example", AsyncComp);
app.mount("#root");
使用 suspense
标签实现页面的呈现
fallback
,否则就显示 default
<div id="root">
<suspense>
<template #default>
<async-example>async-example>
template>
<template #fallback>
<div>loading...div>
template>
suspense>
div>
$children
实例 property 已从 Vue 3.0 中移除,不再支持。$refs
<div id="root">
<h1>scroll down the pageh1>
<input type="range" min="0" max="500" v-model="pinPadding" />
<p v-pin:[direction]="pinPadding">textp>
div>
const app = Vue.createApp({
data() {
return {
pinPadding: 200,
direction: "right",
};
},
});
// app.directive('pin', {
// mounted(el, binding) {
// // console.log(binding)
// el.style.position = 'fixed'
// const s = binding.arg || 'top'
// el.style[s] = binding.value + 'px'
// },
// updated(el, binding) {
// const s = binding.arg || 'top'
// el.style[s] = binding.value + 'px'
// },
// })
// app.directive 第二个参数传一个方法 结果等同于上边 mouthed和updated的结合
app.directive("pin", (el, binding) => {
el.style.position = "fixed";
const s = binding.arg || "top";
el.style[s] = binding.value + "px";
});
app.mount("#root");
定制内置元素
在普通元素上使用时,它将作为 is
attribute 传递给 createElement
调用,并作为原生 attribute 渲染。这支持了自定义内置元素的用法。
<button is="plastic-button">点击我!button>
2.x 的行为:渲染 plastic-button
组件。
3.x 的行为:通过调用以下函数渲染原生的 button
document.createElement("button", { is: "plastic-button" });
使用 vue: 前缀来解决 DOM 内模板解析问题,可以渲染组件
<div id="root">
<div :is="myDiv">div>
<table>
<tr is="vue:mytr">tr>
table>
div>
const app = Vue.createApp({
data() {
return {
myDiv: "abc",
};
},
});
app.component("mytr", {
template: `
abc111
`,
});
app.mount("#root");
1> setup()
基本使用
<template>
<div>{{count}}div>
template>
import { ref } from "vue";
export default {
setup() {
const count = ref(0);
return {
count,
};
},
};
访问 Prop
toRef toRefs
// props: ['title', 'obj']
const x = toRef(props.obj, "x");
const title = toRef(props, "title");
const {
title: title2,
obj: { value },
} = toRefs(props);
setup 的上下文
slots emit attrs expose
// 不给父组件暴露任何数据
// 正常情况下父组件可以通过 $refs 获取子组件的值,这样的情况下,父组件是无法获取内容的
expose();
// attrs 类似于 $attrs ,包含通过子组件标签传来的内容
// emit 就是 $emit
与渲染函数裿使用
<template>
<h1>{{count}}h1>
template>
<script>
import { ref, h, onMounted } from 'vue'
export default {
setup(props, { expose }) {
const count = ref(0)
// return {
// count
// }
onMounted(() => {
setTimeout(() => {
count.value = 100
}, 2000)
})
expose({count})
return () => h('div', {class: 'abc'}, h('a', {href: 'http://www.baidu.com'}, '百度'))
}
}
</script>
2> 核心
ref()
const couter = ref(0);
const obj = ref({
x: 1,
t: {
a: 2,
},
});
reactive()
const obj = reactive({
count,
});
obj.count = 200;
console.log(count.value); // 200
const books = reactive([ref("JavaScript学习指南")]);
books[0].value = "html学习指南";
console.log(books[0].value); // html学习指南
computed()
const count = ref(0);
const addOne = computed(() => count.value + 1);
console.log(addOne.value); // 1
count.value++;
console.log(addOne.value); // 2
readonly()
const original = reactive({ count: 0 });
const copy = readonly(original);
original.count = 100;
// copy.count = 200
console.log(copy.count);
watchEffect()
const count = ref(0);
const stop = watchEffect(() => console.log(count.value));
count.value = 100; // 会打印 100
stop();
// const title = ref('line1')
// const stop = watchEffect(() => console.log(count.value + title.value))
// count.value = 100
// count.value = 100
// title.value = 'line2' // 只打印一次 100line2
watch()
const state = reactive({ count: 0 });
watch(
() => state.count,
(count, prevCount) => {
console.log(count);
console.log(prevCount);
}
);
state.count++; // 1 ,0
3> 工具
isRef()
const count = ref(0);
console.log(isRef(count));
unRef()
const count = ref(10);
const value = unref(count);
toref()
const countObj = reactive({ x: 0, y: 100, z: 300 });
const countObj = reactive({ x: 0, y: 100, z: 300 });
const x = toRef(countObj, "x");
const { x: x1, y, z } = toRefs(countObj);
toRefs()
// 看上面
isProxy()
const msg = reactive({});
const msg2 = {};
console.log(isProxy(msg)); // true
console.log(isProxy(msg2)); // false
isReactive()
const count = ref(0);
const count2 = reactive({ x: 0, y: 0 });
console.log(isReactive(count)); // false
console.log(isReactive(count2)); // true
isReadonly()
const msg = readonly(reactive({}));
const msg2 = ref(0);
console.log(isReadonly(msg)); // true
console.log(isReadonly(msg2)); // false
4> 声明周期钩子
beforeCreate
-> setup()
created
-> setup()
beforeMount
-> onBeforeMount
mounted
-> onMounted
beforeUpdate
-> onBeforeUpdate
updated
-> onUpdated
beforeDestroy
-> onBeforeUnmount
destroyed
-> onUnmounted
setup() {
const count = ref(0)
onMounted(() => {
console.log('onMounted')
count.value = 100
})
onUpdated(() => {
console.log('onUpdated')
})
onUnmounted(() => {
console.log('onUnmounted')
})
onBeforeMount(() => {
console.log('onBeforeMount')
})
onBeforeUpdate(() => {
console.log('onBeforeUpdate')
})
onBeforeUnmount(() => {
console.log('onBeforeUnmount')
})
return {
count
}
}
5> 依赖注入- provide & inject
和之前的 provide & inject 用法是一样的
provide()
const title = ref('hello111')
provide('title1',title)
inject()
const title = inject('title1')
6>
7> Vue Router 4.x 组合式API
在 vite 下安装 Vue Router 4.x
pnpm i vue-router@4
定义路由
import { createRouter, createWebHistory } from 'vue-router'
createWebHistory
history 模式路由
createWebHashHistory
hash 模式路由
引入路由
import router from './router'
app.use(router)
useRouter(),useRoute()
页面中要是用 原来的 router 和 route 需要引入
import { useRouter, useRoute } from 'vue-router'
const router = useRouter();
const route = useRoute();
router.push({
name: "home",
query: {
...route.query,
},
});
watch 路由变化
watch(
() => route.params.id,
(newId) => {
console.log(newId);
}
);
onBeforeRouteLeave() 守卫
onBeforeRouteUpdate() 守卫
8> 21、Vuex 4.x 组合式API
在 vite 下安装 Vuex
pnpm install vuex@next --save
定义 store
import { createStore } from "vuex";
const store = createStore({
state() {
return {
count: 0,
};
},
mutations: {
increment(state) {
state.count++;
},
},
});
export default store;
引入 store
import store from "./store";
app.use(store);
useStore()
import { useStore } from 'vuex'
const store = useStore();
// 取值
const count = computed(() => {
return store.state.count;
});
// 使用方法
const increment = () => {
store.commit("increment");
};