toc
在html文件中引入vue
vue
<body>
<div id="app">
<h1> {{ count }} </h1>
<button @click="count++">count+1</button>
</div>
// type = module是必须要写的,因为要使用es6的import语法
<script type="module">
import { createApp, ref } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
createApp({
setup() {
const count = ref(0)
return {
count
}
}
}).mount("#app")
</script>
</body>
脚手架
1,安装node环境之后,就会有npm命令 2,npm create vue@latest
3,安装文心快码插件
setup语法糖
vue
<!-- 相当于写了setup函数并且return -->
<script setup lang="ts">
const name = 'hello'
</script>
<script lang="ts">
// 定义组件名称,可以不写,但是为了调试方便,建议写上
export default {
name: 'App'
}
</script>
<template>
<h1>{{name}}</h1>
</template>
计算属性
vue
<script setup lang="ts">
import { computed, ref } from 'vue'
const name = ref('张三')
// 只读的computed,不能修改值
let fullname = computed(() => `${name.value} Lee`)
// 可读写的computed,可以修改值
let fullname2 = computed({
get: () => `${name.value} Lee`,
set: (val) => {
console.log(val);
name.value = val;
},
})
function changeName() {
fullname2.value = "李四 Lee"
}
</script>
<template>
<input type="text" v-model="name">
<h1>{{ fullname2 }}</h1>
<button @click="changeName">change full name</button>
</template>
ref & reactive 定义对象类型响应式数据
ref的value响应式对象是reactive实现的
toRefs & toRef
将响应式对象中的每个属性转为ref对象
toRefs是批量转换
vue
<script setup lang="ts">
import { reactive,toRef,toRefs } from 'vue'
const person = reactive({
name: '张三',
age: 18
})
// 解构出来 const {name,age} = person; name和age不是响应式的,person.name是响应式
// 所以修改name的值只是name的值变了,person.name的值不变
// 解决方法是使用toRefs或toRef, 将name转为响应式引用
// let name = toRef(person,'name')
let {name, age} = toRefs(person)
function changeName() {
name.value += "~"
console.log(name.value, person.name);
// 张三~~~~~~~ 张三
}
</script>
<template>
<h1>{{name}}</h1>
<br>
<button @click="changeName">change name</button>
</template>
watch监视
watch监视ref定义的基本类型数据
jsx
const count = ref(0)
// watch 监听ref定义的数据源,当数据变化时执行回调函数, watchStop是停止监视的函数
const watchStop = watch(count, (newVal, old) => {
console.log(newVal, old)
if (newVal === 10) {
// 停止监听
watchStop()
}
})
watch监视ref定义的对象类型数据
监视的是对象的地址值,要想监视个别属性变化,需要开启深度监视
vue
<script setup lang="ts">
import { ref, watch } from 'vue'
let person = ref({
name: 'zhangsan',
age: 18
})
// changeName 并不会触发 watch 监听器
function changeName() {
person.value.name = 'lisi'
}
function changePerson() {
// 会触发 watch 监听器 因为改变了整个对象引用
person.value = {name: 'wangwu', age: 20}
}
watch(person, (newVal, oldVal) => {
console.log(newVal, oldVal)
})
// 总结:监视ref对象类型数据,监视的是对象的地址值,如果要监听对象内部属性的变化,需要使用深度监听。
watch(person, (newVal, oldVal) => {
console.log(newVal, oldVal)
}, {deep: true})
</script>
<template>
<h1>{{person.name}}</h1>
<br>
<button @click="changeName">change name</button>
<button @click="changePerson">change person</button>
</template>
watch监视reactive定义的对象类型数据,默认开启了深度监视
vue
<script setup lang="ts">
import { watch, reactive } from 'vue'
let person = reactive({
name: 'zhangsan'
})
// watch 能深度监视对象内部属性的变化,且深度监视无法stop
function changeName() {
person.name += '~'
}
function changePerson() {
Object.assign(person, { name: 'lisi' })
}
watch(person, (newValue, oldValue) => {
console.log(newValue, oldValue)
})
</script>
<template>
<h1>{{person.name}}</h1>
<br>
<button @click="changeName">change name</button>
<button @click="changePerson">change person</button>
</template>
watch监视对象类型数据中的某个属性
1,若属性不是对象类型,需要写成函数式
2,若属性是对象类型,可以直接写,建议写成函数式
vue
<script setup lang="ts">
import { watch, reactive } from 'vue'
let person = reactive({
name: 'zhangsan',
hobby: {
h1: '篮球',
h2: '足球'
}
})
// 这种方式监视所有属性变化,如果只想监视name的变化,可以使用监视函数的形式,监视支持getter、ref、reactive和他们的数组形式。
// watch(person, (newVal, oldVal) => {
// console.log('newVal', newVal, oldVal)
// })
// 函数式,这样就只监视name的变化了。如果要监视多个属性,可以使用数组的形式。
// 监视响应式对象中的基本类型,要写成函数式
// watch(() => person.name, (newVal, oldVal) => {
// console.log('getter', newVal, oldVal)
// })
// 这样能监视hobby单个h1、h2的变化,但是不能监视hobby对象本身的变化
// watch(person.hobby, (newVal, oldVal) => {
// console.log('hobby:', newVal, oldVal)
// })
// 如果要监视hobby对象本身的变化,需要写成函数式。但是这样监视不到h1、h2的变化。如果要监视到,可以deep监视。
watch(() => person.hobby, (newVal, oldVal) => {
console.log('hobby:', newVal, oldVal)
})
</script>
<template>
<h1>姓名:{{person.name}}</h1>
<h2>爱好:{{ person.hobby.h1 }}、{{ person.hobby.h2 }}</h2>
<br>
<button @click="person.name = 'lisi'">修改姓名</button>
<button @click="person.hobby.h1 += '~'">修改h1</button>
<button @click="person.hobby.h2 += '='">修改h2</button>
<button @click="person.hobby = {h1: '悠悠球', h2: '乒乓球'}">修改hobby</button>
</template>
watch监视多个数据
vue
<template>
<h1>{{person.name}}</h1>
<h1>{{person.age}}</h1>
<h1>{{person.hobbies}}</h1>
<h1>{{person.car}}</h1>
<button @click="changeName">change name</button>
<button @click="changeCar">change car</button>
</template>
<script lang="ts" setup>
import { reactive, ref, watch } from 'vue'
let person = reactive({
name: '张三',
age: 18,
hobbies: ['抽烟', '喝酒', '烫头'],
car: {
c1: '奔驰',
c2: '宝马'
}
})
function changeName() {
person.name = '李四'
}
function changeCar() {
person.car.c1 = '特斯拉'
}
// 结合前几种情况,如果要同时监听多个响应式对象的变化,可以使用数组的形式
watch([()=>person.name, ()=>person.car.c1], (value) => {
console.log(value);
})
</script>
watchEffect全监视
vue
<template>
<h1>temp>60 | height>80时,触发监视</h1>
<h1>{{ temp }}</h1>
<h1>{{ height }}</h1>
<button @click="changeTemp">change temp</button>
<button @click="changeHeight">change height</button>
</template>
<script lang="ts" setup>
import { ref, watch, watchEffect } from "vue";
let temp = ref(10);
let height = ref(0);
function changeTemp() {
temp.value += 10;
}
function changeHeight() {
height.value += 10;
}
// 明确指出需要监视的属性,监视多个响应式引用时使用数组格式
watch([temp, height], ([t, h]) => {
if (t > 60 && h > 80) {
console.log("触发监视watch");
}
});
watchEffect(() => {
// 页面启动就触发监视,依赖发生变化时也会触发监视
console.log("触发watchEffect监视");
if (temp.value > 60 && height.value > 80) {
console.log("触发监视watchEffect");
}
});
</script>
标签的ref属性
ref放到普通html标签上
下面的代码,正常会输出 <h2>甄子丹</h2>
vue
<template>
<h1>李小龙</h1>
<h2>甄子丹</h2>
<button @click="changeH2">点我输出h2元素</button>
</template>
<script lang="ts" setup>
function changeH2(){
console.log(document.querySelector('h2'))
}
</script>
但如果index.html里面是这样的
html
<body>
<h2>李长鸿</h2>
<div id="app">
</div>
<script type="module" src="/src/main.js"></script>
</body>
那么获取到的h2就是<h2>李长鸿</h2>
了
不同文件中或不同组件中如果元素一样,使用js方式获取到的元素无法明确区分,包括通过id取元素,如果id不同文件中有重复就无法区分
vue
<template>
<h1>李小龙</h1>
<h2 id="title2">甄子丹</h2>
<button @click="changeH2">点我输出h2元素</button>
</template>
<script lang="ts" setup>
function changeH2(){
console.log(document.getElementById('title2'))
}
</script>
解决这个问题就是使用ref,这样会不同文件相互隔离,互不影响
vue
<template>
<h1>李小龙</h1>
<h2 ref="title2">甄子丹</h2>
<button @click="changeH2">点我输出h2元素</button>
</template>
<script lang="ts" setup>
import { ref } from "vue";
let title2 = ref();
function changeH2() {
console.log(title2.value);
}
</script>
ref放到组件上
ref拿到的是组件实例,如果想打印出组件里面的属性,需要使用defineExpose
vue
<template>
<Person ref="ren"> </Person>
<button @click="changePerson">点我输出person元素</button>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import Person from "@/components/Person.vue";
// 创建一个title2的响应式引用,用于存储ref标记的h2元素
let ren = ref();
function changePerson() {
// 输出的是标签实例的引用,而非DOM元素,但是输出的内容看不到person里的属性,因为它是组件实例对象
console.log(ren.value);
}
</script>
Person.vue组件
vue
<template>
<h2 class="person">{{name}}</h2>
</template>
<script lang="ts">
export default {
name: 'Person',
}
</script>
<script lang="ts" setup>
import { ref, defineExpose } from "vue";
const name = ref("张三");
defineExpose({name})
</script>
局部样式
元素内容属性 data-xxx就是局部样式,主要是style样式加了scope引起,<style scoped>
html
<h2 data-v-7a7a37b1="">甄子丹</h2>