使用vue-cli创建:
- ## 查看@vue/cli版本,确保@vue/cli版本在4.5.0以上
- vue --version
- ## 安装或者升级你的@vue/cli
- npm install -g @vue/cli
- ## 创建
- vue create vue_test
- ## 启动
- cd vue_test
- npm run serve
使用vite创建:
官方文档:快速上手 | Vue.js
- ## 创建工程
- npm init vite-app
- ## 进入工程目录
- cd
- ## 安装依赖
- npm install
- ## 运行
- npm run dev
官方文档: 组合式 API 常见问答 | Vue.js
- <template>
- <h1>一个人的信息</h1>
- <h2>姓名:name</h2>
- <h2>年龄:age</h2>
- <button @click="sayHello">说话</button>
- </template>
-
- <script>
- //import h from 'vue'
- export default {
- name: 'App',
- // 此处只是测试setup(),不考虑响应式问题。
- setup() {
- // 数据
- let name = '张三'
- let age = 18
-
- // 方法
- function sayHello() {
- alert(`我叫${name},我${age}岁了,你好啊!`)
- }
- // 返回一个对象(常用)
- return {
- name,
- age,
- sayHello
- }
- // 返回一个渲染函数
- // return () => h('h1', '尚硅谷')
- }
- }
- </script>
6.setup的两个注意点
- <template>
- <h1>一个人的信息</h1>
- <h2>姓名:{{name}}</h2>
- <h2>年龄:{{age}}</h2>
- <h3>工作:{{job.type}}</h3>
- <h3>薪水:{{job.salary}}</h3>
- <button @click="changeInfo">修改人的信息</button>
- </template>
-
- <script>
- import {ref} from 'vue'
- export default {
- name: 'App',
- setup() {
- // 数据
- let name = ref('张三')
- let age = ref(18)
- let job = ref({
- type: '前端工程师',
- salary: '20k'
- })
-
- function changeInfo() {
- // name.value = '李四'
- // age.value = 49
- job.value.type = '后端工程师'
- job.value.salary = '60k'
- console.log(job.value)
- }
-
- // 返回一个对象(常用)
- return {
- name,
- age,
- job,
- changeInfo
- }
- }
- }
- </script>
- <template>
- <h1>一个人的信息</h1>
- <h2>姓名:{{person.name}}</h2>
- <h2>年龄:{{person.age}}</h2>
- <h3>工作:{{person.job.type}}</h3>
- <h3>薪水:{{person.job.salary}}</h3>
- <h4>测试数据c: {{person.job.a.b.c}}</h4>
- <h4>测试数据hobby:{{person.hobby[0]}}</h4>
- <button @click="changeInfo">修改人的信息</button>
- </template>
-
- <script>
- import {reactive} from 'vue'
- export default {
- name: 'App',
- setup() {
- // 数据
- let person = reactive({
- name: '张三',
- age: 18,
- job:{
- type: '前端工程师',
- salary: '20k',
- a: {
- b: {
- c: 666
- }
- }
- },
- hobby:['抽烟', '喝酒', '烫头'],
- })
-
-
- //方法
- function changeInfo() {
- person.name.value = '李四'
- person.age.value = 49
- person.job.type = '后端工程师'
- person.job.salary = '60k'
- person.job.a.b.c = 999
- person.hobby[0] = '学习'
- }
-
- // 返回一个对象(常用)
- return {
- person,
- changeInfo
- }
-
- }
- }
- </script>
---------------------------------------------------------
- Object.defineProperty(data, 'count', {
- get () {},
- set () {}
- })
- <script type="text/javascript">
- const person = {
- name: '张三',
- age: 14
- }
- // 模拟Vue3中实现响应式
- const p = new Proxy(person, {
- // 有人读取某个属性时,调用
- get(target, propName) {
- console.log(`有人读取了p身上的${propName}属性`)
- return target[propName]
- },
- // 有人修改或增加某个属性时,调用
- set(target, propName, value) {
- console.log(`有人修改了p身上的${propName}属性,我要去更新页面了!`)
- target[propName] = value
- },
- // 有人删除某个属性时,调用
- deleteProperty(target, propName) {
- console.log(`有人删除了p身上的${propName}属性,我要去更新页面了!`)
- return delete target[propName]
- }
- })
- script>
- new Proxy(data, {
- // 拦截读取属性值
- get (target, prop) {
- return Reflect.get(target, prop)
- },
- // 拦截设置属性值或添加新属性
- set (target, prop, value) {
- return Reflect.set(target, prop, value)
- },
- // 拦截删除属性
- deleteProperty (target, prop) {
- return Reflect.deleteProperty(target, prop)
- }
- })
-
- proxy.name = 'tom'
-----------------------------------------------
与Vue2.x中computed配置功能一致
- import {computed} from 'vue'
-
- setup(){
- ...
- //计算属性——简写
- let fullName = computed(()=>{
- return person.firstName + '-' + person.lastName
- })
- //计算属性——完整
- let fullName = computed({
- get(){
- return person.firstName + '-' + person.lastName
- },
- set(value){
- const nameArr = value.split('-')
- person.firstName = nameArr[0]
- person.lastName = nameArr[1]
- }
- })
- }
- //情况一:监视ref定义的响应式数据
- watch(sum,(newValue,oldValue)=>{
- console.log('sum变化了',newValue,oldValue)
- },{immediate:true})
-
- //情况二:监视多个ref定义的响应式数据
- watch([sum,msg],(newValue,oldValue)=>{
- console.log('sum或msg变化了',newValue,oldValue)
- })
-
- /* 情况三:监视reactive定义的响应式数据
- 若watch监视的是reactive定义的响应式数据,则无法正确获得oldValue!!
- 若watch监视的是reactive定义的响应式数据,则强制开启了深度监视
- */
- watch(person,(newValue,oldValue)=>{
- console.log('person变化了',newValue,oldValue)
- },{immediate:true,deep:false}) //此处的deep配置不再奏效
-
- //情况四:监视reactive定义的响应式数据中的某个属性
- watch(()=>person.job,(newValue,oldValue)=>{
- console.log('person的job变化了',newValue,oldValue)
- },{immediate:true,deep:true})
-
- //情况五:监视reactive定义的响应式数据中的某些属性
- watch([()=>person.job,()=>person.name],(newValue,oldValue)=>{
- console.log('person的job变化了',newValue,oldValue)
- },{immediate:true,deep:true})
-
- //特殊情况
- watch(()=>person.job,(newValue,oldValue)=>{
- console.log('person的job变化了',newValue,oldValue)
- },{deep:true}) //此处由于监视的是reactive素定义的对象中的某个属性,所以deep配置有效
- //watchEffect所指定的回调中用到的数据只要发生变化,则直接重新执行回调。
- watchEffect(()=>{
- const x1 = sum.value
- const x2 = person.age
- console.log('watchEffect配置的回调执行了')
- })
Vue3.0中可以继续使用Vue2.x中的生命周期钩子,但有有两个被更名:
Vue3.0也提供了 Composition API 形式的生命周期钩子,与Vue2.x中钩子对应关系如下:
src/hooks/usePoint.js
- import { reactive, onMounted, onUnmounted } from "vue"
-
- export default function() {
- // 实现鼠标打点的数据
- let point = reactive({
- x:0,
- y:0
- })
- // 实现鼠标打点的方法
- function savePoint(event) {
- point.x = event.pageX
- point.y = event.pageY
- }
- // 实现鼠标打点的钩子
- onMounted(()=>{
- window.addEventListener('click', savePoint)
- })
-
- onUnmounted(() => {
- window.removeEventListener('click', savePoint)
- })
-
- return point
- }
使用:
- <script>
- import {ref} from 'vue'
- import usePoint from '../hooks/usePoint'
- export default {
- name: 'MyDemo',
- setup() {
- let sum = ref(0)
- let point = usePoint()
-
- return {
- sum,
- point
- }
- }
- }
- </script>
- <template>
- <h2>姓名:{{name}}</h2>
- <h2>年龄:{{age}}</h2>
- <h2>薪资:{{job.j1.salary}}K</h2>
- <button @click="name+='~'">修改姓名</button>
- <button @click="age++">修改年龄</button>
- <button @click="job.j1.salary++">涨薪</button>
- </template>
-
- <script>
- import {reactive, toRefs} from 'vue'
- export default {
- setup() {
- let person = reactive({
- name: '张三',
- age: 18,
- job: {
- j1: {
- salary: 2000
- }
- }
- })
- return {
- // name: toRef(person, 'name'),
- // age: toRef(person, 'age'),
- // salary:toRef(person.job.j1, 'salary'),
- ...toRefs(person)
- }
- }
- }
- </script>
- <template>
- <h4>当前的x.y值是:{{x.y}}</h4>
- <button @click="x={y:888}">点我替换x</button>
- <button @click="x.y++">点我x.y++</button>
- <hr>
- <h4>{{person}}</h4>
- <h2>姓名:{{name}}</h2>
- <h2>年龄:{{age}}</h2>
- <h2>薪资:{{job.j1.salary}}K</h2>
- <button @click="name+='~'">修改姓名</button>
- <button @click="age++">增长年龄</button>
- <button @click="job.j1.salary++">涨薪</button>
- </template>
-
- <script>
- import {ref,reactive,toRef,toRefs,shallowReactive,shallowRef} from 'vue'
- export default {
- name: 'Demo',
- setup(){
- //数据
- // let person = shallowReactive({ //只考虑第一层数据的响应式
- let person = reactive({
- name:'张三',
- age:18,
- job:{
- j1:{
- salary:20
- }
- }
- })
- let x = shallowRef({
- y:0
- })
- console.log('******',x)
-
- //返回一个对象(常用)
- return {
- x,
- person,
- ...toRefs(person)
- }
- }
- }
- </script>
- <template>
- <h4>当前求和为:{{sum}}</h4>
- <button @click="sum++">点我++</button>
- <hr>
- <h2>姓名:{{name}}</h2>
- <h2>年龄:{{age}}</h2>
- <h2>薪资:{{job.j1.salary}}K</h2>
- <button @click="name+='~'">修改姓名</button>
- <button @click="age++">增长年龄</button>
- <button @click="job.j1.salary++">涨薪</button>
- </template>
-
- <script>
- import {ref,reactive,toRefs,readonly,shallowReadonly} from 'vue'
- export default {
- name: 'Demo',
- setup(){
- //数据
- let sum = ref(0)
- let person = reactive({
- name:'张三',
- age:18,
- job:{
- j1:{
- salary:20
- }
- }
- })
-
- person = readonly(person)
- // person = shallowReadonly(person)
- // sum = readonly(sum)
- // sum = shallowReadonly(sum)
-
- //返回一个对象(常用)
- return {
- sum,
- ...toRefs(person)
- }
- }
- }
- </script>
- <template>
- <h4>当前求和为:{{sum}}</h4>
- <button @click="sum++">点我++</button>
- <hr>
- <h2>姓名:{{name}}</h2>
- <h2>年龄:{{age}}</h2>
- <h2>薪资:{{job.j1.salary}}K</h2>
- <h3 v-show="person.car">座驾信息:{{person.car}}</h3>
- <button @click="name+='~'">修改姓名</button>
- <button @click="age++">增长年龄</button>
- <button @click="job.j1.salary++">涨薪</button>
- <button @click="showRawPerson">输出最原始的person</button>
- <button @click="addCar">给人添加一台车</button>
- <button @click="person.car.name+='!'">换车名</button>
- <button @click="changePrice">换价格</button>
- </template>
-
- <script>
- import {ref,reactive,toRefs,toRaw,markRaw} from 'vue'
- export default {
- name: 'Demo',
- setup(){
- //数据
- let sum = ref(0)
- let person = reactive({
- name:'张三',
- age:18,
- job:{
- j1:{
- salary:20
- }
- }
- })
-
- function showRawPerson(){
- const p = toRaw(person)
- p.age++
- console.log(p)
- }
-
- function addCar(){
- let car = {name:'奔驰',price:40}
- person.car = markRaw(car)
- }
-
- function changePrice(){
- person.car.price++
- console.log(person.car.price)
- }
-
- //返回一个对象(常用)
- return {
- sum,
- person,
- ...toRefs(person),
- showRawPerson,
- addCar,
- changePrice
- }
- }
- }
- </script>
- <template>
- <input type="text" v-model="keyword">
- <h3>{{keyword}}</h3>
- </template>
-
- <script>
- import {ref,customRef} from 'vue'
- export default {
- name:'Demo',
- setup(){
- // let keyword = ref('hello') //使用Vue准备好的内置ref
- //自定义一个myRef
- function myRef(value,delay){
- let timer
- //通过customRef去实现自定义
- return customRef((track,trigger)=>{
- return{
- get(){
- track() //告诉Vue这个value值是需要被“追踪”的
- return value
- },
- set(newValue){
- clearTimeout(timer)
- timer = setTimeout(()=>{
- value = newValue
- trigger() //告诉Vue去更新界面
- },delay)
- }
- }
- })
- }
- let keyword = myRef('hello',500) //使用程序员自定义的ref
- return {
- keyword
- }
- }
- }
- </script>
- setup(){
- ......
- let car = reactive({name:'奔驰',price:'40万'})
- provide('car',car)
- ......
- }
- setup(props,context){
- ......
- const car = inject('car')
- return {car}
- ......
- }
Options API 存在的问题:使用传统OptionsAPI中,新增或者修改一个需求,就需要分别在data,methods,computed里修改 。
Composition API 的优势:我们可以更加优雅的组织我们的代码,函数。让相关功能的代码更加有序的组织在一起。
- <teleport to="移动位置">
- <div v-if="isShow" class="mask">
- <div class="dialog">
- <h3>我是一个弹窗</h3>
- <button @click="isShow = false">关闭弹窗</button>
- </div>
- </div>
- </teleport>
等待异步组件时渲染一些额外内容,让应用有更好的用户体验
异步引入组件:
- import {defineAsyncComponent} from 'vue'
- const Child = defineAsyncComponent(()=>import('./components/Child.vue'))
使用Suspense包裹组件,并配置好default 与 fallback:
- <template>
- <div class="app">
- <h3>我是App组件</h3>
- <Suspense>
- <template v-slot:default>
- <Child/>
- </template>
- <template v-slot:fallback>
- <h3>加载中.....</h3>
- </template>
- </Suspense>
- </div>
- </template>
- //注册全局组件
- Vue.component('MyButton', {
- data: () => ({
- count: 0
- }),
- template: ''
- })
-
- //注册全局指令
- Vue.directive('focus', {
- inserted: el => el.focus()
- }
2.x 全局 API(Vue) | 3.x 实例 API (app) |
Vue.config.xxxx | app.config.xxxx |
Vue.config.productionTip | 移除 |
Vue.component | app.component |
Vue.directive | app.directive |
Vue.mixin | app.mixin |
Vue.use | app.use |
Vue.prototype | app.config.globalProperties |
- .v-enter,
- .v-leave-to {
- opacity: 0;
- }
- .v-leave,
- .v-enter-to {
- opacity: 1;
- }
- .v-enter-from,
- .v-leave-to {
- opacity: 0;
- }
-
- .v-leave-from,
- .v-enter-to {
- opacity: 1;
- }
- <my-component
- v-on:close="handleComponentEvent"
- v-on:click="handleNativeClickEvent"
- />
- <script>
- export default {
- emits: ['close']
- }
- </script>