Skip to content

aiyaya211/vue3.0

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

35 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

demo

Project setup

yarn install

Compiles and hot-reloads for development

yarn serve

Compiles and minifies for production

yarn build

Lints and fixes files

yarn lint

Customize configuration

See Configuration Reference.

vue3.0学习

组合式API和选项式API

学习vue2.x的时候没有这个区分的概念,当时使用的其实就是选项式API
vue3其实是对vue2.x中的选项式API的兼容,在学习vue3的过程中,更提倡使用选项式API,文档中提到的很多的知识点,也是基于选项式API

setup生命周期

reactive() 返回的是一个原始对象的 Proxy,适用于引用数据类型
ref() 适用于基本数据类型

计算属性

计算属性是响应式的,通过computed()函数接收一个getter函数实现,返回一个计算属性ref

const author = reactive({
    name: 'aiyaya',
    weather: 'sunny',
    address: '杭州',
    mood: 'lose job'
})
// 一个计算属性 ref
const publishedBooksMessage = computed(() => {
    return author.weather === 'sunny' ? 'Yes' : 'No'
})
<div>计算属性</div>
<!-- 计算属性 ref 也会在模板中自动解包 -->
<div>{{ publishedBooksMessage }}</div>  

v-if和v-show的优先级关系

vue3vue2的一个不同点,v-ifv-for同时使用的优先级是不一样的,vue3中,当 v-ifv-for 同时存在于一个元素上的时候,v-if 会首先被执行,但是我们在实际开发过程中不要把这两个放在同一个元素上,通过外层添加template或者使用计算属性来实现我们的需求

生命周期

beforeCreate阶段获取不到计算属性(已声明未赋值,不会报错),能获取到propscreated阶段能获取到计算属性

beforeCreate() {
    console.log(`beforeCreate + ${this.author}`); // undefined
},
created() {
    console.log(`created + ${this.author}`); // aiyaya
},
computed: {
    author() {
        return 'aiyaya';
    }
},

监听函数

vue3中直接给 watch() 传入一个响应式对象,会隐式地创建一个深层侦听器——该回调函数在所有嵌套的变更时都会被触发,vue2需要加参数deep
一个返回响应式对象的 getter 函数,只有在返回不同的对象时,才会触发回调,这个时候如果需要深度侦听还是需要deep选项

函数模板引用

组件传值

vue2中父组件传值给子组件使用的是props属性,vue3中改用defineProps

新增createApp方法

创建节点挂载到指定dom

import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')

可以多个挂载点挂载

<!-- 有app和app1两个挂载点 -->
<div id="app"></div>
<div id="app1"></div>

类似一个挂载一个的方式进行多个组件的挂载

响应式

因为vue3中的响应式是基于proxy实现的

export default {
  data() {
    return {
      someObject: {}
    }
  },
  mounted() {
    const newObject = {}
    this.someObject = newObject

    console.log(newObject === this.someObject) // false
  }
}

当你在赋值后再访问 this.someObject,此值已经是原来的 newObject 的一个响应式代理。与 Vue 2 不同的是,这里原始的 newObject 不会变为响应式:请确保始终通过 this 来访问响应式状态。(官方原话)
意思就是data中的响应式数据,在赋值操作后,赋值生成的拷贝对象和原本的对象不是同一个,也无法像data中的数据一样可以响应式。

nextTick需要引入api之后方可使用.

import { nextTick } from 'vue';
mounted() {
        nextTick(() => {
            console.log('nextTick')
        })
 },

若不做import引入,vue3.0中会报错

v-model在自定义组件中的应用

默认情况下,组件上的v-model使用modelValue作为propupdate:modelValue作为事件。我们可以通过向v-model传递参数来修改这些名称:

<!--子组件-->
    <button @click="changeTitle">子组件向父组件传值</button>
// 子组件
export default {
 props: {
        title: {
            type: String,
            default: 'Default title'
        },
        name: {
            type: String,
            default: 'Default name'
        }
    },
 methods: {
        changeTitle() {
            this.$emit('update:title', `aiyaya's title`);
            this.$emit('update:name', `aiyaya's name`);
        }
    }
}
<!--父组件-->
  <MyComponent v-model:title="pageTitle" v-model:name="parentName"></MyComponent>
// 父组件
export deafault {
	data() {
    return {
      pageTitle: 'this is vue3.0',
      parentName: 'this is parentName',
    }
  }
}

vue3.0中自定义组件v-model支持自定义修饰符

关于自定义组件v-model自定义修饰符,有个疑问:

<!--父组件-->
  <MyComponent v-model:title="pageTitle" v-model:name="parentName" v-model.capitalize:modelValue="myText"></MyComponent>

这种写法,会不生效

mixin合并行为变更

// mixin.js
export default {
    data() {
        return {
            user: {
                name: 'aiyaya',
                id: 1
              }
        }
    }
}
// 组件 vue3.0
mixins: [componentMixin],
 data() {
    return {
        user: {
            id: 2
        }
    }
},
 mounted() {
    nextTick(() => {
        console.log('nextTick');
        console.log(`data: ${JSON.stringify(this.$data)}`); //data: {"user":{"id":2}}
    })
},
// 组件 vue2.*
 nextTick(() => {
        console.log('nextTick');
        console.log(`data: ${JSON.stringify(this.$data)}`); //data: {"user":{name: 'aiyaya',"id":2}}
 })

自定义指令生命周期调整

自定义指令的生命周期与组件的生命周期一致
vue2.*

  • bind - 指令绑定到元素后发生。只发生一次。
  • inserted - 元素插入父 DOM 后发生。
  • update - 当元素更新,但子元素尚未更新时,将调用此钩子。
  • componentUpdated - 一旦组件和子级被更新,就会调用这个钩子。
  • unbind - 一旦指令被移除,就会调用这个钩子。也只调用一次。

vue3.0

  • bind → beforeMount
  • inserted → mounted
  • beforeUpdate:新的!这是在元素本身更新之前调用的,很像组件生命周期钩子。
  • update → 移除!有太多的相似之处要更新,所以这是多余的,请改用 updated。
  • componentUpdated → updated
  • beforeUnmount:新的!与组件生命周期钩子类似,它将在卸载元素之前调用。
  • unbind -> unmounted

非vue3.0知识点

非 Prop 的 Attribute $attrs属性指的是从上级组件传到下级组件,但是在子组件中并没有相应 propsemits定义的attribute,非prop的attribute。
$attrs一般会直接挂载到根元素上。

<!--子组件 my-select-->
    <select>
      <option value="1">Yesterday</option>
      <option value="2">Today</option>
      <option value="3">Tomorrow</option>
    </select>
// 子组件 中能获取到 未定义的 attrs onchange事件
// select 自带 change 的事件监听
 created() {
    console.log('myselect');
    console.log(this.$attrs.onChange);  //     changeOpt(val) {/*code*/}
 },
<!--父组件-->
  <my-select @change="changeOpt"></my-select>
// 父组件
 methods: {
    changeOpt(val) {
      console.log(val.target.value); //yesterday || today ||. tomorrow
    }
  }

需要注意的是,$attrs只能默认挂载在根节点上,举个例子:

<!--子组件-->
<template>
    <div>
        <div>{{name}}</div>
    </div>
</template>
// 子组件props 不包含age
 props: {
        name: String,
        sex: String,
    },
<!--父组件-->
<child-a name="aiyaya" sex="girl" age="20"></child-a>

<!--渲染结果 age属性在最外层的根元素上-->
<div age="20">
    <div>aiyaya</div>
</div>

provide/inject
provide/inject主要用于深嵌套的父组件给子组件传值
对于如下的组件结构:

todoList.vue  
│
└───todoItem.vue
  │
  └───todoBtn.vue
<!--todoList.vue-->
<todo-item></todo-item>
export default {
    provide() {
        return {
            startComponent: 'todolist',
            todoLength: this.items.length
        }
    },
}
<!--todoItem.vue-->
<template>
    <todo-btn></todo-btn>
</template>
<!--todoBtn.vue-->
<template>
    <button type="text">{{startComponent}}</button>
</template>
// todoBtn.vue
export default {
    name: 'todo-btn',
    inject: ['startComponent', 'todoLength'], // 注入
    data() {
        return {}
    }
}

todoBtn.vue渲染效果:

<button type="text">todolist</button>

并且能在created()生命周期中访问到被注入的属性

// todoBtn.vue
created() {
    console.log(`created startComponent: ${this.startComponent} todolistlength: ${this.todoLength}`) 
    // created startComponent: todolist todolistlength: 4
},

传入teleport
当不使用teleport 实现一个全屏的弹窗

<!--子组件 弹窗 modal-button-->
<template>
    <button @click="modalOpen = true">
        展开全屏模式
    </button>
    <div v-if="modalOpen" class="modal">
      <div>
        I'm a modal! 
        <button @click="modalOpen = false">
          关闭全屏模式
        </button>
      </div>
    </div>
</template>
<script>
export default {
    name: "model-button",
    data() {
        return {
            modalOpen: false,
        }
    }
}
</script>
<style>
.modal {
    position:absolute;
    left:0px;
    top:0px;
    width:100%;
    height:100%;
    background: azure;
}
</style>

挂载到父组件中

<!--父组件 因为是全屏 根据css定位需要将父组件根节点设置为position:  relative-->
<template>
 <div style="position: relative;">
   <modal-button></modal-button>
 </div>
 </template>

传入 teleport的作用就是给子组件一个相对定位的点,修改子组件如下:

<template>
    <button @click="modalOpen = true">
        展开全屏模式
    </button>
    <teleport to="body">
    <div v-if="modalOpen" class="modal">
      <div>
        I'm a modal! 
        <button @click="modalOpen = false">
          关闭全屏模式1
        </button>
      </div>
    </div>
    </teleport>
</template>

去掉父组件的相对定位 ,全屏弹窗依旧可以实现,可以看下渲染得到的页面代码:

About

vue3.0学习记录

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published