1、环境准备:
nodejs 14.0.0+
我装了16.16.0
环境变量配置好了就可以使用npm了
npm install vue@next
2、创建项目
然后安装vite,vite在这一步会自动帮你创建一个vue3项目
npm init vite@latest
打开上一步创建的文件夹后,执行npm install,再npm run dev,即可启动项目
3、打包
npm run build
产生的包在根目录中的dist文件夹
4、语法(大部分都是跟vue2一样)
4.1 v-once
{{…}} 标签的内容将会被替代为对应组件实例中 message 属性的值,如果 message 属性的值发生了改变,{{…}} 标签内容也会更新。
如果不想改变标签的内容,可以通过使用 v-once 指令执行一次性地插值,当数据改变时,插值处的内容不会更新。
<span v-once>这个将不会改变: {{ message }}</span>
4.2 v-html
使用 v-html 指令用于输出 html 代码:
<p>使用 v-html 指令: <span v-html="rawHtml"></span></p>
data() {
return {
rawHtml: '<span style="color: red">这里会显示红色!</span>'
}
}
4.3 v-if
v-if 是一个指令,所以必须将它添加到一个元素上。如果是多个元素,可以包裹在 <template>
元素上,并在上面使用 v-if。最终的渲染结果将不包含 <template>
元素。
4.4 v-for
v-for 除了可以遍历数组,也可以遍历Object、整数,用法与vue2相同
5、组件
const app = Vue.createApp({...})
app.component('my-component-name', {
/* ... */
})
my-component-name 为组件名,/* … */ 部分为配置选项。注册后,我们可以使用以下方式来调用组件:
<my-component-name></my-component-name>
5.1 props
多种类型,用数组限制类型,
object,需要function return{}
限制传入值,使用如下最后一个
Vue.component('my-component', {
props: {
// 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
propA: Number,
// 多个可能的类型
propB: [String, Number],
// 必填的字符串
propC: {
type: String,
required: true
},
// 带有默认值的数字
propD: {
type: Number,
default: 100
},
// 带有默认值的对象
propE: {
type: Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function () {
return { message: 'hello' }
}
},
// 自定义验证函数
propF: {
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
})
6、事件
Vue.js 为 v-on 提供了事件修饰符来处理 DOM 事件细节,如:event.preventDefault() 或 event.stopPropagation()。
Vue.js 通过由点 . 表示的指令后缀来调用修饰符。
- .stop - 阻止冒泡
- .prevent - 阻止默认事件
- .capture - 阻止捕获
- .self - 只监听触发该元素的事件
- .once - 只触发一次
- .left - 左键事件
- .right - 右键事件
- .middle - 中间滚轮事件
按键修饰符
Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:
<input v-on:keyup.13="submit">
<!-- 同上 -->
<input v-on:keyup.enter="submit">
<!-- 缩写语法 -->
<input @keyup.enter="submit">
全部的按键别名:
- .enter
- .tab
- .delete (捕获 “删除” 和 “退格” 键)
- .esc
- .space
- .up
- .down
- .left
- .right
系统修饰键:
- .ctrl
- .alt
- .shift
- .meta
鼠标按钮修饰符:
- .left
- .right
- .middle
.exact 修饰符
<!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
<button @click.ctrl="onClick">A</button>
<!-- 有且只有 Ctrl 被按下的时候才触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>
<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button @click.exact="onClick">A</button>
7、表单
v-model 会根据控件类型自动选取正确的方法来更新元素。
v-model 会忽略所有表单元素的 value、checked、selected 属性的初始值,使用的是 data 选项中声明初始值。
- v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:
- text 和 textarea 元素使用 value 属性和input 事件;
- checkbox 和 radio 使用 checked 属性和 change 事件;
- select 字段将 value 作为属性并将 change 作为事件。
7.1 修饰符
.lazy
在默认情况下, v-model 在 input 事件中同步输入框的值与数据,但你可以添加一个修饰符 lazy ,从而转变为在 change 事件中同步:
<!-- 在 "change" 而不是 "input" 事件中更新 -->
<input v-model.lazy="msg" >
.number
如果想自动将用户的输入值转为 Number 类型(如果原值的转换结果为 NaN 则返回原值),可以添加一个修饰符 number 给 v-model 来处理输入值:
<input v-model.number="age" type="number">
这通常很有用,因为在 type=“number” 时 HTML 中输入的值也总是会返回字符串类型。
.trim
如果要自动过滤用户输入的首尾空格,可以添加 trim 修饰符到 v-model 上过滤输入:
<input v-model.trim="msg">
8、Vue3 自定义指令directive
vnode
作为 el 参数收到的真实 DOM 元素的蓝图。
prevNode
上一个虚拟节点,仅在 beforeUpdate 和 updated 钩子中可用。
app.directive('runoob', (el, binding, vnode) => {
console.log(binding.value.name) // => "菜鸟教程"
console.log(binding.value.url) // => "www.runoob.com"
var s = JSON.stringify
el.innerHTML = s(binding.value)
})
9、router
router-link
请注意,我们没有使用常规的 a 标签,而是使用一个自定义组件 router-link 来创建链接。这使得 Vue Router 可以在不重新加载页面的情况下更改 URL,处理 URL 的生成以及编码。我们将在后面看到如何从这些功能中获益。
router-view
router-view 将显示与 url 对应的组件。你可以把它放在任何地方,以适应你的布局。
// 1. 定义路由组件.
// 也可以从其他文件导入
const Home = { template: '<div>Home</div>' }
const About = { template: '<div>About</div>' }
// 2. 定义一些路由
// 每个路由都需要映射到一个组件。
// 我们后面再讨论嵌套路由。
const routes = [
{ path: '/', component: Home },
{ path: '/about', component: About },
]
// 3. 创建路由实例并传递 `routes` 配置
// 你可以在这里输入更多的配置,但我们在这里
// 暂时保持简单
const router = VueRouter.createRouter({
// 4. 内部提供了 history 模式的实现。为了简单起见,我们在这里使用 hash 模式。
history: VueRouter.createWebHashHistory(),
routes, // `routes: routes` 的缩写
})
// 5. 创建并挂载根实例
const app = Vue.createApp({})
//确保 _use_ 路由实例使
//整个应用支持路由。
app.use(router)
app.mount('#app')
// 现在,应用已经启动了!
router-link 相关属性
- to
表示目标路由的链接。 当被点击后,内部会立刻把 to 的值传到 router.push(),所以这个值可以是一个字符串或者是描述目标位置的对象。
<!-- 字符串 -->
<router-link to="home">Home</router-link>
<!-- 渲染结果 -->
<a href="home">Home</a>
<!-- 使用 v-bind 的 JS 表达式 -->
<router-link v-bind:to="'home'">Home</router-link>
<!-- 不写 v-bind 也可以,就像绑定别的属性一样 -->
<router-link :to="'home'">Home</router-link>
<!-- 同上 -->
<router-link :to="{ path: 'home' }">Home</router-link>
<!-- 命名的路由 -->
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
<!-- 带查询参数,下面的结果为 /register?plan=private -->
<router-link :to="{ path: 'register', query: { plan: 'private' }}">Register</router-link>
- replace
设置 replace 属性的话,当点击时,会调用 router.replace() 而不是 router.push(),导航后不会留下 history 记录。
<router-link :to="{ path: '/abc'}" replace></router-link>
- append
设置 append 属性后,则在当前 (相对) 路径前添加其路径。例如,我们从 /a 导航到一个相对路径 b,如果没有配置 append,则路径为 /b,如果配了,则为 /a/b
<router-link :to="{ path: 'relative/path'}" append></router-link>
- tag
有时候想要 router-link 渲染成某种标签,例如 li。 于是我们使用 tag prop 类指定何种标签,同样它还是会监听点击,触发导航。
<router-link to="/foo" tag="li">foo</router-link>
<!-- 渲染结果 -->
<li>foo</li>
- active-class
设置 链接激活时使用的 CSS 类名。可以通过以下代码来替代。 - exact-active-class
配置当链接被精确匹配的时候应该激活的 class。可以通过以下代码来替代。 - event
声明可以用来触发导航的事件。可以是一个字符串或是一个包含字符串的数组。
<router-link v-bind:to = "{ path: '/route1'}" event = "mouseover">Router Link 1</router-link>
以上代码设置了 event 为 mouseover ,及在鼠标移动到 Router Link 1 上时导航的 HTML 内容会发生改变。
10.Mixin混入
- 选项合并
- 变量重名,使用组件值覆盖了
- 同名钩子函数将合并为一个数组,因此都将被调用。另外,mixin 对象的钩子将在组件自身钩子之前调用。
- 值为对象的选项,例如 methods、components 和 directives,将被合并为同一个对象。两个对象键名冲突时,取组件对象的键值对。
综上
来个例子,图二是Vue3写法
setup 组件
- setup() 函数在组件创建 created() 之前执行。
setup() 函数接收两个参数 props 和 context。
第一个参数 props,它是响应式的,当传入新的 prop 时,它将被更新。
第二个参数 context 是一个普通的 JavaScript 对象,它是一个上下文对象,暴露了其它可能在 setup 中有用的值。
注意:在 setup 中你应该避免使用 this,因为它不会找到组件实例。setup 的调用发生在 data property、computed property 或 methods 被解析之前,所以它们无法在 setup 中被获取。
- 在 Vue 3.0 中,我们可以通过一个新的 ref 函数使任何响应式变量在任何地方起作用,如下所示:
import { ref } from 'vue'
let count = ref(0);
- 在 Vue 3.0 中,setup语法糖指令directives写法:
<template>
<div v-click-outside="hide"></div>
</template>
<script lang="ts" setup>
import { ClickOutside as vClickOutside } from '@s-design-basic/directives'
</script>
-
ref() 函数可以根据给定的值来创建一个响应式的数据对象,返回值是一个对象,且只包含一个
.value
属性。在 setup() 函数内,由 ref() 创建的响应式数据返回的是对象,所以需要用
.value
来访问。
setup
import { ref } from 'vue'
const counter = ref(0)
console.log(counter) // { value: 0 }
console.log(counter.value) // 0
counter.value++
console.log(counter.value) // 1
模板引用
在使用组合式 API 时,响应式引用和模板引用的概念是统一的。
为了获得对模板内元素或组件实例的引用,我们可以像往常一样声明 ref 并从 setup() 返回:
<template>
<div ref="root">This is a root element</div>
</template>
<script>
import { ref, onMounted } from 'vue'
export default {
setup() {
const root = ref(null)
onMounted(() => {
// DOM 元素将在初始渲染后分配给 ref
console.log(root.value) // <div>This is a root element</div>
})
return {
root
}
}
}
</script>
以上实例中我们在渲染上下文中暴露 root,并通过 ref=“root”,将其绑定到 div 作为其 ref。
作为模板使用的 ref 的行为与任何其他 ref 一样:它们是响应式的,可以传递到 (或从中返回) 复合函数中。
侦听模板引用
侦听模板引用的变更可以替代前面例子中演示使用的生命周期钩子。
但与生命周期钩子的一个关键区别是,watch() 和 watchEffect() 在 DOM 挂载或更新之前运行会有副作用,所以当侦听器运行时,模板引用还未被更新。
因此,使用模板引用的侦听器应该用 flush: ‘post’ 选项来定义,这将在 DOM 更新后运行副作用,确保模板引用与 DOM 保持同步,并引用正确的元素。
<template>
<div ref="root">This is a root element</div>
</template>
<script>
import { ref, watchEffect } from 'vue'
export default {
setup() {
const root = ref(null)
watchEffect(() => {
console.log(root.value) // => <div>This is a root element</div>
},
{
flush: 'post'
})
return {
root
}
}
}
</script>
- 基本类型值(
String
、Nmuber
、Boolean
等)或单值对象(类似像 {count: 3} 这样只有一个属性值的对象)使用ref
- 引用类型值(
Object
、Array
)使用reactive
ref
是对传入数据的拷贝;toRef
是对传入数据的引用ref
的值改变会更新视图;toRef
的值改变不会更新视图
shallowReactive
听这个API的名称就知道,这是一个浅层的 reactive,难道意思就是原本的 reactive 是深层的呗,没错,这是一个用于性能优化的API
只有第一层被 Proxy
处理了,也就是说只有修改第一层的值时,才会响应式更新
shallowReactive
监听了第一层属性的值,一旦发生改变,则更新视图
shallowRef
同上
如果需要更新视图 triggerRef
,调用它就可以立马更新视图,其接收一个参数 state ,即需要更新的 ref 对象
toRaw
toRaw
方法是用于获取 ref
或 reactive
对象的原始数据的
即获取最原始的数据格式,不用RefImpl
或者Proxy
对象包裹
markRaw
markRaw
方法可以将原始数据标记为非响应式的,即使用 ref
或 reactive
将其包装,仍无法实现数据响应式,其接收一个参数,即原始数据,并返回被标记后的数据
provide && inject
provide
:向子组件以及子孙组件传递数据。接收两个参数,第一个参数是 key,即数据的名称;第二个参数为 value,即数据的值inject
:接收父组件或祖先组件传递过来的数据。接收一个参数 key,即父组件或祖先组件传递的数据名称
watch && watchEffect详细demo举例,此处说明出处https://juejin.cn/post/6897030228867022856
watch:watch( source, cb, [options] )
参数说明:
- source:可以是表达式或函数,用于指定监听的依赖对象
- cb:依赖对象变化后执行的回调函数
- options:可参数,可以配置的属性有 immediate(立即触发回调函数)、deep(深度监听)
接下来再来聊聊 watchEffect,它与 watch 的区别主要有以下几点:
- 不需要手动传入依赖
- 每次初始化时会执行一次回调函数来自动获取依赖
- 无法获取到原值,只能得到变化后的值