Vue3
声明式渲染
使用模板语法
<div id="counter">
Counter: {{ counter }}
</div>
创建vue应用并且挂载
const Counter = {
data() {
return {
counter: 0
}
}
}
Vue.createApp(Counter).mount('#counter')
绑定属性
v-bind: attribute
简写
:attribute
事件监听
v-on: event
简写
@: event
双向数据绑定
v-model
条件与循环
条件:v-if="条件"
v-else
循环:v-for: item in any[]
组件化应用构建
//创建组件
const todoItem = {
template: '<li>123</li>'
}
//创建vue实例
const app = Vue.createApp({
components: {
todoItem
}
})
app.mount(...)
在别的组件导入并且使用
<ol>
<!-- 创建一个 todo-item 组件实例 -->
<todo-item></todo-item>
</ol>
父传子
创建子组件
const TodoItem = {
props: ['todo'],
template: `<li>{{ todo.text }}</li>`
}
<ol>
<!-- 创建一个 todo-item 组件实例 -->
<todo-item :todo="传入值"></todo-item>
</ol>
根组件
把一个vue应用挂载到<div id="app"></div>
const RootComponent = {
/* 选项 */
}
const app = Vue.createApp(RootComponent)
const vm = app.mount('#app')
生命周期
xxxx
Data Property
组件的data是一个函数,组件调用的时候执行并且返回一个对象,vue通过响应系统将其包裹起来,并且以$data的形式存储;
const app = Vue.createApp({
data() {
return {
count: 3
}
}
})
const vm = app.mount('#app');
console.log(vm.$data.count); // 3
方法methods
Vue自动为methods
绑定this
,指向组件的实例
计算属性
<div>
<p>
{{ publicFunc }}
</p>
<p>
{{ Func() }}
</p>
</div>
Vue.createApp({
data() {
return {
count: 0
}
},
computed: {
publicFunc() {
return this.count > 0 ? 'yes' : 'no'
}
},
methods: {
Func() {
return this.count > 0 ? 'yes' : 'no'
}
}
}).mount('#app')
计算属性和方法的区别就是计算属性跟响应依赖相关联,多次调用计算属性只要相关联的响应依赖没有发生改变的情况下就不会调用,函数则无论有无改变都会调用。
计算属性存取器
//...
computed: {
fullName: {
get() {
return this.xxxx
},
set(newValue) {
执行的方法
}
}
}
当我们对fullName的值修改的时候就会执行set方法
侦听器watch
xxxxx
class绑定
<div :class="{ active: isActive, text-danger: !isActive }">
</div>
active
的类名是否存在取决于isActive
:class
可以和普通的class
共存
还有数组语法
<div :class="[activeclass, activeclass2]">
</div>
data: {
return {
activeclass: 'active',
activeclass2: 'active2'
}
}
组件上使用
创建一个组件
const app = Vue.createApp({})
app.component('my-component', {
template: '<p class="foo"> </p> '
})
使用的时候添加class不会覆盖原有的class
<div>
<my-component class="boo"></my-component>
</div>
渲染为
<div>
<p class="foo boo">
</p>
</div>
绑定内联样式
对象语法
<div :style="{ color: activeColor, fontSize: fontSize + 'px'}">
</div>
<div :style="object">
</div>
数组语法
把多个对象绑定到内联样式
<div :style="[baseStyles, overridingStyles]"></div>
多重值
只会渲染最后一个被浏览器支持的值
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
v-if和v-show
v-if
是销毁和重建
v-show
是只是css的隐藏
列表渲染
数组
<div v-for="(item, index) in array" :key="item">
</div>
对象
<div v-for="(value, name, index) in object" :key="value">
</div>
数组更新检测方法
只有对原本的数组进行改变的数组方法才能更新检测,返回新数组的方法不能检测
事件处理
<div @click="func('123', $event)">
</div>
<div @click="func2">
</div>
func(value, event) {
}
func2(event) {
//不传参默认参数为event
}
多事件处理
<div @click="func('123', $event), two($event)">
</div>
事件修饰符
<!-- 阻止单击事件继续冒泡 -->
<a @click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form @submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a @click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form @submit.prevent></form>
<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div @click.capture="doThis">...</div>
<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div @click.self="doThat">...</div>
按键修饰符
<input @keyup.enter="submit" />
Vue 为最常用的键提供了别名:
.enter
.tab
.delete
(捕获“删除”和“退格”键)
.esc
.space
.up
.down
.left
.right
系统按键修饰符
<!-- Alt + Enter -->
<input @keyup.alt.enter="clear" />
<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>
待写。。。。。
组合式API
vue2.0的复用组件可以提高我们的代码可维护性和灵活性,但是如果应用变得特别的大的时候共享和重用代码变得尤其重要。
组合式API基础
setup组件选项
1、首先,在setup
中应该避免使用this,因为他不会指向组件实例。
2、setup
的调用发生在data
、computed
、methods
解析之前。
setup
接受一个参数props
和context
把setup
添加到组件当中
这是子组件,父组件传值user
为0
<script>
export default {
props: {
user: {
type: String,
required: true
}
},
setup(props, context) {
//props为 { user: 0 }
return {} //返回值可以在组件的其他地方使用
}
}
</script>
我们声明一个变量在setup里面return出去
setup(props, context) {
cosnt value = 0
setTimeout(() => {
value = 1
}, 2000)
return {
value
}
}
我们把这个变量放到渲染模板,值并没有变化,说明变量不是响应式的。
带ref的响应式变量
<script>
import { ref } from 'vue';
export default {
props: {
user: {
type: String,
required: true
}
},
setup(props, context) {
const value = ref(0); // { value: 0 }
setTimeout(() => {
value.value = 1
})
return {
value
}
}
}
</script>
模板
<template>
<div>
{{value}}
</div>
</template>
setup注册生命周期钩子
创建一个异步函数在onMounted里面调用
<script>
import { ref, onMounted } from 'vue';
export default {
//...
setup(props, context) {
const value = ref(0); // { value: 0 }
const func = () => {
setTimeout(() => {
value = 123
}, 2000)
}
onMounted(func)
return {
value
}
}
}
</script>
watch响应式更改
<script>
import { ref, onMounted, watch } from 'vue';
export default {
//...
setup(props, context) {
const counter = ref(0); // { value: 0 }
const func = () => {
setTimeout(() => {
counter = 123
}, 2000)
}
onMounted(func)
watch(counter, (newValue, oldValue) => {
console.log('The new counter is: ' + counter.value)
})
return {
counter
}
}
}
</script>
可以检测到counter的更改
用toRefs创建对props的user响应式引用
<script>
import { ref, onMounted, watch } from 'vue';
export default {
//...
setup(props, context) {
const { user } = toRefs(props); // { value: 0 }
watch(user, (newValue, oldValue) => {
console.log(user)
})
return {
user
}
}
}
</script>
独立的计算属性
<script>
import { ref, onMounted, watch, computed } from 'vue';
export default {
//...
setup(props, context) {
const { user } = toRefs(props); // { value: 0 }
const newCounter = computed(() => {
return user.value + user.value
})
watch(user, (newValue, oldValue) => {
console.log(user)
})
return {
user,
newCounter
}
}
}
</script>
把代码提取到一个单独的组合式函数
创建一个js文件zuhe.js
import { watch, computed } from 'vue';
export default function useUser(user) {
const newUser = user
const newCounter = computed(() => {
return user.value + user.value
})
watch(user, (newValue, oldValue) => {
console.log(user);
})
return {
newUser,
newCounter
}
}
导入到vue文件中使用
<script>
import { toRefs } from 'vue';
import useUser from './zuhe'
export default {
props: {
user: {
type: String,
required: true
}
},
setup(props) {
const { user } = toRefs(props);
const { newUser, newCounter } = useUser(user)
return {
newUser,
newCounter
}
},
}
</script>
Props
setup的第一个参数,不能使用es6的解构,会消除props的响应性。
如果要解构props就要用
import { toRefs } from 'vue';
setup(props) {
const { title } = toRefs(props)
}
如果title是可选参数那么传入的Props可能没有title,要用toRef来创建一个title。
import { toRef } from 'vue';
setup(props) {
const title = toRef(props, 'title')
}
Context
普通的js对象;
暴露其他可能在setup的值。
可以解构
如:
export default {
setup(props, context) {
//$attr
context.attr
//$slots
context.slots
//$emit
context.emit
//暴露公共的property
context.expose
}
}
访问组件的property
当前只能访问props/attr/emit/slots
无法访问data/computed/methods/refs
的选项
结合模板
<template>
<div>
{{ book.title }}
</div>
</template>
<script>
import { ref, reactive } from 'vue'
export default {
setup() {
const num = ref(0);
const num1 = reactive({ title: 'is title'})
return {
num,
num1
}
}
}
</script>
使用渲染函数
使用vue的渲染函数h
import { h, reactive } from 'vue';
setup(props, { expose }) {
const book = reactive({title: 'is new title'})
return () => h('div', [book.title])
}
但是这有有一个弊端,就是我们不能返回我们处理的其他数据,所以我们要用到expose
.
import { h, reactive } from 'vue';
setup(props, { expose }) {
const book = reactive({title: 'is new title'})
const count = ref('这是count')
expose({
count
})
return () => h('div', [book.title])
}
这有父祖家可以通过ref访问到子组件的count
setup的生命周期钩子函数
选项式API | Hook inside setup |
---|---|
beforeCreate | Not needed* |
created | Not needed* |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeUnmount | onBeforeUnmount |
unmounted | onUnmounted |
errorCaptured | onErrorCaptured |
renderTracked | onRenderTracked |
renderTriggered | onRenderTriggered |
activated | onActivated |
deactivated | onDeactivated |
Provide / Inject
父组件
provide(属性名, 属性值)
import { provide, ref } from 'vue'
setup() {
const value = ref(0)//给value添加响应性
provide('isValue', value)
}
子组件
import { inject, ref } from 'vue'
setup() {
const newValue = inject('isValue', '123');//第一个参数位接受的属性名称,第二个参数位属性的默认值。
return newValue
}
修改响应式的property
尽量对响应式的property的修改控制在provide所在的组件
import { provide, ref } from 'vue'
setup() {
const value = ref(0)//给value添加响应性
provide('isValue', value)
const updateValue = () => {
value.value = 123;
}
provide('updateValue', updateValue)
}
添加readonly改为只读属性,防止在非定义provide的组件内进行修改
import { provide, ref, readonly } from 'vue'
setup() {
const value = ref(0)//给value添加响应性
provide('isValue', readonly(value))
const updateValue = () => {
value.value = 123;
}
provide('updateValue', updateValue)
}
模板引用
再setup中进行模板引用(模板ref)
<template>
<div ref='value'>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
export default {
setup() {
const value = ref(null) //声明的变量的名称要与ref绑定的名称相同
onMounted(() => {
console.log(value.value) //在挂载之后打印.value属性可以访问到dom
})
return {
value
}
}
}
</script>
自定义指令
vue3版本的自定义指令
全局注册自定义指令
import { createApp } from 'vue';
import App from './App.vue';
const vm = createApp(App);//创建vue实例对象
//添加全局自定义事件
vm.directive('[name]', {
inserted: function (el) {
//指令属性
}
})
//挂载
vm.mount('#app')
局部注册
//在export default里面
directives: {
[name]: {
//指令属性
}
}
钩子函数
钩子函数 | 详情 |
---|---|
created | 在绑定元素的attribute和事件监听器(v-on)被应用之前调用 |
beforeMount | 指令第一次绑定到元素并且挂载到父组件之前调用 |
mounted | 在绑定元素的父组件被挂载前调用。 |
beforeUpdate | 在更新包含组件的vNode及其子组件的vNode的时候调用 |
updated | 在包含组件的vnode和子组件的vnode更新的时候调用 |
beforeUnmount | 在卸载绑定元素的父元素的时候调用 |
unmounted | 当指令与元素解除绑定且父组件已经卸载的时候调用一次 |
Teleport
可以将我们需要渲染的组件直接插入选中的标签
app.component('modal-button', {
template:` <teleport to="body">
<div>这是要插入的div</div>
</teleport>`
})
插件
当插件被添加到应用程序的时候,如果是一个对象,就会调用install方法,如果是一个函数则调用函数本身。
创建一个对象形的插件
//js文件
export default {
install: (app, options) => {
app.config.globalProperties.$xxxx = xxx
}
}