Vue只关注视图层,采用自底向上增量开发的设计。
Vue的目标是通过尽可能简单的API实现响应的数据绑定和组合的视图组件。
实例:
1 2 3
| <div id="hello-vue" class="demo"> {{ message }} </div>
|
起步
安装
- 下载文件并引入(vue.global.js)
- cdn引入(vue.global.js)
- npm安装
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| npm install -g cnpm
cnpm install vue@next
cnpm install -g @vue/cli
vue --version
cnpm install -g @vue/cli-init
|
创建项目
1 2 3 4 5
| vue init webpack project_name
cnpm run dev
|
还可以使用Vite构建vue项目。
1 2 3 4 5 6 7 8 9 10 11 12
| cnpm install -g create-vite-app
create-vite-app project_name cva project_name cnpm init vite-app project_name
cd project_name cnpm install cnpm run dev
|
构建
生成dist目录,然后放到服务器。
搭建服务器
1 2 3 4 5
| python -m http.server --directory [dist_dir]
npx http-server
|
目录结构
src/App.vue1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <template> <img alt="Vue logo" src="./assets/logo.png" /> <HelloWorld msg="Hello Vue 3.0 + Vite" /> </template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default { name: 'App', components: {
HelloWorld
} } </script>
|
起步
学习Vue3阶段可以直接引入vue.global.js
文件。
引入vue.global.js1
| <script crossorigin="anonymous" integrity="sha512-+i5dAv2T8IUOP7oRl2iqlAErpjtBOkNtREnW/Te+4VgQ52h4tAY5biFFQJmF03jVDWU4R7l47BwV8H6qQ+/MfA==" src="https://lib.baomitu.com/vue/3.0.7/vue.global.js"></script>
|
Vue3中的应用是通过使用 createApp
函数来创建的,语法格式如下:
1 2 3 4 5 6 7 8 9 10 11
| const app = Vue.createApp({
})
Vue.createApp(HelloVueApp).mount('#hello-vue')
|
实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <div id="hello-vue" class="demo"> {{ message }} </div> <script> const HelloVueApp = { data() { return { message: 'Hello Vue!!' } } } Vue.createApp(HelloVueApp).mount('#hello-vue') </script>
|
data
data
是一个函数,返回一个对象。
vm.$data.count == vm.count
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| const app = Vue.createApp({ data() { return { count: 4 } } })
const vm = app.mount('#app')
document.write(vm.$data.count) document.write("<br>") document.write(vm.count) document.write("<br>")
vm.count = 5 document.write(vm.$data.count) document.write("<br>")
vm.$data.count = 6 document.write(vm.count)
|
methods
可以在组件中添加方法,使用 methods
, methods
是一个对象,包含了多个方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| const app = Vue.createApp({ data() { return { count: 4 } }, methods: { increment() { this.count++ } } })
const vm = app.mount('#app')
document.write(vm.count) document.write("<br>") vm.increment()
document.write(vm.count)
|
在一个方法中调用另一个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| const app = Vue.createApp({ data() { return { } }, methods: { func1() {
}, func2() { this.$options.methods.func1(); } } })
const vm = app.mount('#app')
|
模板语法
插值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| <div id="app"> <p>{{ message }}</p> </div>
<span v-once>这个将不会改变: {{ message }}</span>
<div id="example1" class="demo"> <p>使用双大括号的文本插值: {{ rawHtml }}</p> <p>使用 v-html 指令: <span v-html="rawHtml"></span></p> </div> <script> const RenderHtmlApp = { data() { return { rawHtml: '<span style="color: red">这里会显示红色!</span>' } } }
Vue.createApp(RenderHtmlApp).mount('#example1') </script>
<div v-bind:id="dynamicId"></div>
<button v-bind:disabled="isButtonDisabled">按钮</button>
<div id="app"> <label for="r1">修改颜色</label><input type="checkbox" v-model="use" id="r1"> <br><br> <div v-bind:class="{'class1': use}"> v-bind:class 指令 </div> </div> <script> const app = { data() { return { use: false } } }
Vue.createApp(app).mount('#app') </script>
<div id="app"> {{5+5}}<br> {{ ok ? 'YES' : 'NO' }}<br> {{ message.split('').reverse().join('') }} <div v-bind:id="'list-' + id"></div> </div>
<script> const HelloVueApp = { data() { return { ok: true, message: 'message', id: 1 } } }
Vue.createApp(HelloVueApp).mount('#hello-vue') </script>
|
tips:每个绑定只能包含单个表达式。
指令
指令是带有 v-
前缀的特殊属性。
指令用于在表达式的值改变时,将某些行为应用到DOM上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <div id="app"> <p v-if="seen">现在你看到我了</p> </div>
<script> const app = { data() { return { seen: true } } }
Vue.createApp(app).mount('#app') </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <div id="app"> <ol> <li v-for="site in sites"> {{ site.text }} </li> </ol> </div> <script> const app = { data() { return { sites: [{ text: 'Google' }, { text: 'facebook' }, { text: 'Taobao' } ] } } }
Vue.createApp(app).mount('#app') </script>
|
参数:参数在指令后以冒号指明。
例如: v-bind
指令被用来响应地更新HTML属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <div id="app"> <p><a v-bind:href="url"></a></p> </div>
<script> const HelloVueApp = { data() { return { url: 'https://www.baidu.com' } } }
Vue.createApp(HelloVueApp).mount('#app') </script>
|
v-on:
1 2 3 4 5 6 7 8
| <a v-on:click="doSomething"> ... </a>
<a @click="doSomething"> ... </a>
<a @[event]="doSomething"> ... </a>
|
修饰符:
1
| <form v-on:submit.prevent="onSubmit"></form>
|
输入
v-model
指令用来在input、select、textarea、checkbox、radio等表单控件元素上创建双向数据绑定,根据表单上的值,自动更新绑定的元素的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <div id="app"> <p>{{ message }}</p> <input v-model="message"> </div>
<script> const app = { data() { return { message: 'baidu' } } }
Vue.createApp(app).mount('#app') </script>
|
缩写
Vue.js为两个最为常用的指令提供了特别的缩写:
1 2 3 4 5 6 7 8 9
| <a v-bind:href="url"></a>
<a :href="url"></a>
<a v-on:click="doSomething"></a>
<a @click="doSomething"></a>
|
条件语句
条件判断使用 v-if
指令,指令的表达式返回 true
时才会显示。
v-if
v-else
v-else-if
v-show
使用 v-show
指令来根据条件展示元素:
1
| <h1 v-show="ok">Hello!</h1>
|
tips: 这里注意v-if和v-show的区别。
循环语句
循环使用 v-for
指令。
v-for
指令需要以 site in sites
形式的特殊语法, sites
是源数据数组并且 site
是数组元素迭代的别名。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <div id="app"> <ol> <li v-for="site in sites"> {{ site.text }} </li> </ol> </div> <script> const app = { data() { return { sites: [{ text: 'Google' }, { text: 'baidu' }, { text: 'Taobao' } ] } } }
Vue.createApp(app).mount('#app') </script>
|
v-for
还支持一个可选的第二个参数,参数值为当前项的索引:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <div id="app"> <ol> <li v-for="(site, index) in sites"> {{ index }} -{{ site.text }} </li> </ol> </div> <script> const app = { data() { return { sites: [{ text: 'Google' }, { text: 'baidu' }, { text: 'Taobao' } ] } } }
Vue.createApp(app).mount('#app') </script>
|
v-for迭代对象
v-for
可以通过一个对象的属性来迭代数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <div id="app"> <ul> <li v-for="value in object"> {{ value }} </li> </ul> </div>
<script> const app = { data() { return { object: { name: '链接', url: 'http://www.baidu.com', slogan: '学的不仅是技术,更是梦想!' } } } }
Vue.createApp(app).mount('#app') </script>
|
也可以提供第二个的参数为键名:
1 2 3 4 5 6 7
| <div id="app"> <ul> <li v-for="(value, key) in object"> {{ key }} : {{ value }} </li> </ul> </div>
|
第三个参数为索引:
1 2 3 4 5 6 7
| <div id="app"> <ul> <li v-for="(value, key, index) in object"> {{ index }}. {{ key }} : {{ value }} </li> </ul> </div>
|
v-for
迭代整数:
1 2 3 4 5 6 7
| <div id="app"> <ul> <li v-for="n in 10"> {{ n }} </li> </ul> </div>
|
显示过滤/排序后的结果:可以对数组的元素进行处理后再显示出来,一般可以通过创建一个计算属性,来返回过滤或排序后的数组。
1 2 3 4 5 6
| <div id="app"> <ul> <li v-for="n in evenNumbers">{{ n }}</li> </ul> </div>
|
组件
注册组件
组件(Component)可以扩展HTML元素,封装可重用的代码。
可以使用多个组件构建大型应用。
注册全局组件:
1 2 3 4 5 6 7
| const app = Vue.createApp({ ... })
app.component('my-component', {
})
|
使用该组件:
1
| <my-component></my-component>
|
vue组件实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <div id="app"></div>
<script> const app = Vue.createApp({})
app.component('componentA', { template: '<h1>组件A</h1>' })
app.mount('#app') </script>
|
实例: button-counter
组件,在每次点击后,计数器会加1。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <script> const app = Vue.createApp({})
app.component('button-counter', { data() { return { count: 0 } }, template: ` <button @click="count++"> 点了 {{ count }} 次! </button> ` })
app.mount('#app') </script>
|
组件复用
组件可以多次复用:
1 2 3 4 5
| <div id="components-demo"> <button-counter></button-counter> <button-counter></button-counter> <button-counter></button-counter> </div>
|
全局组件
注册全局组件:
1 2 3 4 5 6 7 8 9 10 11 12 13
| <div id="app"> <baidu></baidu> </div>
<script> const app = Vue.createApp({})
app.component('globalComponent', { template: '<h1>全局组件</h1>' })
app.mount('#app') </script>
|
局部组件
可以通过一个js对象来定义组件,然后在 components
字段中定义要使用的组件:
1 2 3 4 5 6 7 8 9 10
| const componentA = {
} const componentB = {
} const componentC = {
}
|
1 2 3 4 5 6 7 8
| const app = Vue.createApp({ components: { 'component-a': componentA, 'component-b': componentB } })
|
实例中的局部组件,只能在该实例中使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <div id="app"> <part-component></part-component> </div>
<script> var partComponent = { template: '<h1>局部组件</h1>' }
const app = Vue.createApp({ components: { 'part-component': partComponent } })
app.mount('#app') </script>
|
prop
prop
是子组件用来接受父组件传递的数据的属性。
父组件通过 props
将数据传给子组件,子组件需要用 props
声明 prop
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <div id="appo"> <site-name title="Google"> </site-namet> <site-name title="baidu"> </site-namet> <site-name title="Taobao"></site-name> </div>
<script> const app = Vue.createApp({})
app.component('site-name', { props: ['title'], template: `<h4>{{ title }}</h4>` })
app.mount('#app') </script>
|
动态prop:
可以使用 v-bind
动态绑定props的值到父组件的数据中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| <div id="app"> <site-info v-for="site in sites" :id="site.id" :title="site.title"></site-info> </div>
<script> const Site = { data() { return { sites: [{ id: 1, title: 'Google' }, { id: 2, title: 'baidu' }, { id: 3, title: 'Taobao' } ] } } }
const app = Vue.createApp(Site)
app.component('site-info', { props: ['id', 'title'], template: `<h4>{{ id }} - {{ title }}</h4>` })
app.mount('#app') </script>
|
prop验证:
组件可以给 props
指定验证条件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| Vue.component('my-component', { props: { 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 } } } })
|
type
可以是下面原生构造器:
- String
- Number
- Boolean
- Array
- Object
- Date
- Function
- Symbol
type
也可以是一个自定义构造器,使用 instanceof
检测。
$emit
$emit
用于子组件向父组件传递数据。
具体方法是:子组件使用 $emit
触发自定义事件,父组件使用 v-on
指令监听子组件的自定义事件。
1 2
| vm.$emit(eventName, [...args]);
|
.sync
父组件调用子组件时使用sync修饰符可以做到父子组件的属性的双向数据绑定。
1 2
| <child :value.sync="val"></child>
|
计算
计算: computed
实例:反转字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <div id="app"> <p>原始字符串: {{ message }}</p> <p>计算后反转字符串: {{ reversedMessage }}</p> </div>
<script> const app = { data() { return { message: 'baidu!!' } }, computed: { reversedMessage: function() { return this.message.split('').reverse().join('') } } }
Vue.createApp(app).mount('#app') </script>
|
computed vs methods
可以使用 methods
代替 computed
。
但是computed依赖缓存,只有依赖关系发生变化才会重新计算。
而methods在重新渲染时总是会重新执行。
1 2 3 4 5
| methods: { reversedMessage2: function() { return this.message.split('').reverse().join('') } }
|
computed setter
computed属性默认只有 getter
,也可以设置 setter
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| var vm = new Vue({ el: '#app', data: { name: 'Google', url: 'http://www.google.com' }, computed: { site: { get: function() { return this.name + ' ' + this.url }, set: function(newValue) { var names = newValue.split(' ') this.name = names[0] this.url = names[names.length - 1] } } } })
vm.site = '百度 http://www.baidu.com'; document.write('name: ' + vm.name); document.write('<br>'); document.write('url: ' + vm.url);
|
监听
可以使用监听属性 watch
来响应数据变化。
使用watch实现计数器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <div id="app"> <p style="font-size:25px;">计数器: {{ counter }}</p> <button @click="counter++" style="font-size:25px;">点我</button> </div>
<script> const app = { data() { return { counter: 1 } } } vm = Vue.createApp(app).mount('#app') vm.$watch('counter', function(nval, oval) { alert('计数器值的变化 :' + oval + ' 变为 ' + nval + '!'); }); </script>
|
样式绑定
可以使用 v-bind
绑定属性,可以绑定字符串、对象、数组。
v-bind:class
=== :class
绑定class
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <div :class="{'active': isActive }"></div>
<div class="active"></div>
<div class=""></div>
<div class="static" :class="{ 'active' : isActive, 'text-danger' : hasError }"></div>
<div class="static" :class="classObject"></div>
|
绑定数组
1 2 3 4 5
| <div class="static" :class="[activeClass, errorClass]"></div>
<div class="static" :class="[isActive ? activeClass : '', errorClass]"></div>
|
style
可以 v-bind:style
设置内联样式。
1
| <div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
|
可以直接绑定到一个样式对象:
1
| <div :style="styleObject"></div>
|
使用数组将多个样式对象绑定到一个元素上:
1
| <div :style="[baseStyles, overridingStyles]"></div>
|
可以给css样式同一个属性提供不同的值:
1
| <div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
|
组件中使用class
下面四个class都会有:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <div id="app"> <baidu class="classC classD"></baidu> </div>
<script> const app = Vue.createApp({})
app.component('baidu', { template: '<h1 class="classA classB">I like baidu!</h1>' })
app.mount('#app') </script>
|
如果组件有多个根元素,通过 $attrs
属性定义那些部分接受这个class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <div id="app"> <baidu class="classA"></baidu> </div>
<script> const app = Vue.createApp({})
app.component('baidu', { template: ` <p :class="$attrs.class">I like baidu!</p> <span>这是一个子组件</span> ` })
app.mount('#app') </script>
|
事件处理
可以使用 v-on
监听DOM事件。
v-on
可以缩写为 @
。
1 2 3
| v-on:click="func"
@click="func"
|
v-on
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <div id="app"> <button @click="counter += 1">增加 1</button> <p>这个按钮被点击了 {{ counter }} 次。</p> </div>
<script> const app = { data() { return { counter: 0 } } }
Vue.createApp(app).mount('#app') </script>
|
实例2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <div id="app"> <button @click="greet">点我</button> </div>
<script> const app = { data() { return { name: 'baidu' } }, methods: { greet(event) { alert('Hello ' + this.name + '!') if (event) { alert(event.target.tagName) } } } }
Vue.createApp(app).mount('#app') </script>
|
实例3:可以绑定多个方法,逗号隔开
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <div id="app"> <button @click="one($event), two($event)"> 点我 </button> </div>
<script> const app = { data() {}, methods: { one(event) { alert("第一个事件处理器逻辑...") }, two(event) { alert("第二个事件处理器逻辑...") } } }
Vue.createApp(app).mount('#app') </script>
|
事件修饰符
Vue通过由点 .
表示的指令后缀来调用修饰符。
.stop
- 阻止冒泡
.prevent
- 阻止默认事件
.capture
- 阻止捕获
.self
- 只监听触发该元素的事件
.once
- 只触发一次
.left
- 左键事件
.right
- 右键事件
.middle
- 中间滚轮事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <a v-on:click.stop="doThis"></a>
<form v-on:submit.prevent="onSubmit"></form>
<a v-on:click.stop.prevent="doThat"></a>
<form v-on:submit.prevent></form>
<div v-on:click.capture="doThis">...</div>
<div v-on:click.self="doThat">...</div>
<a v-on:click.once="doThis"></a>
|
按键修饰符
Vue允许为 v-on
在监听键盘事件时添加按键修饰符:
1 2
| <input v-on:keyup.13="submit">
|
记住所有的 keyCode 比较困难,所以 Vue 为最常用的按键提供了别名:
1 2 3 4
| <input v-on:keyup.enter="submit">
<input @keyup.enter="submit">
|
全部的按键别名:
- .enter
- .tab
- .delete (捕获 “删除” 和 “退格” 键)
- .esc
- .space
- .up
- .down
- .left
- .right
系统修饰键:
鼠标按钮修饰符:
1 2 3 4 5
| <p> <input @keyup.alt.67="clear"> <div @click.ctrl="doSomething">Do something</div>
|
.exact修饰符
.exact
允许精准控制系统修饰符组合触发的事件。
1 2 3 4 5 6 7 8
| <button @click.ctrl="onClick">A</button>
<button @click.ctrl.exact="onCtrlClick">A</button>
<button @click.exact="onClick">A</button>
|
表单
可以使用 v-model
在 input
、 textarea
和 select
等元素上创建双向数据绑定。
v-model
会忽略所有表单元素的value、checked、selected属性的初始值,使用的是data选项中声明初始值。
v-model在内部为不同的输入元素使用不同的属性并抛出不同的事件:
- text和textarea元素使用value属性和input事件;
- checkbox和radio使用checked属性和change事件;
- select字段将value作为属性并将change作为事件。
使用v-model实现双向数据绑定:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <div id="app"> <p>input 元素:</p> <input v-model="message" placeholder="编辑我……"> <p>input 表单消息是: {{ message }}</p>
<p>textarea 元素:</p> <textarea v-model="message2" placeholder="多行文本输入……"></textarea> <p>textarea 表单消息是:</p> <p style="white-space: pre">{{ message2 }}</p>
</div>
<script> const app = { data() { return { message: '', message2: '百度\r\nhttps://www.baidu.com' } } }
Vue.createApp(app).mount('#app') </script>
|
在文本区域 textarea 插值是不起作用,需要使用 v-model 来代替:
1 2 3 4 5
| <textarea>{{ text }}</textarea>
<textarea v-model="text"></textarea>
|
复选框双向数据绑定:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <div id="app"> <p>单个复选框:</p> <input type="checkbox" id="checkbox" v-model="checked"> <label for="checkbox">{{ checked }}</label>
<p>多个复选框:</p> <input type="checkbox" id="baidu" value="baidu" v-model="checkedNames"> <label for="baidu">baidu</label> <input type="checkbox" id="google" value="Google" v-model="checkedNames"> <label for="google">Google</label> <input type="checkbox" id="taobao" value="Taobao" v-model="checkedNames"> <label for="taobao">taobao</label> <br> <span>选择的值为: {{ checkedNames }}</span> </div>
<script> const app = { data() { return { checked: false, checkedNames: [] } } }
Vue.createApp(app).mount('#app') </script>
|
单选按钮:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <div id="app"> <input type="radio" id="baidu" value="baidu" v-model="picked"> <label for="baidu">baidu</label> <br> <input type="radio" id="google" value="Google" v-model="picked"> <label for="google">Google</label> <br> <span>选中值为: {{ picked }}</span> </div>
<script> const app = { data() { return { picked: 'baidu' } } }
Vue.createApp(app).mount('#app') </script>
|
select:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <div id="app"> <select v-model="selected" name="fruit"> <option value="">选择一个网站</option> <option value="www.baidu.com">baidu</option> <option value="www.google.com">Google</option> </select>
<div id="output"> 选择的网站是: {{selected}} </div> </div>
<script> new Vue({ el: '#app', data: { selected: '' } }) </script>
|
v-for:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <div id="app" class="demo"> <select v-model="selected"> <option v-for="option in options" :value="option.value"> {{ option.text }} </option> </select> <span>选择的是: {{ selected }}</span> </div>
<script> const app = { data() { return { selected: 'www.baidu.com', options: [{ text: 'baidu', value: 'www.baidu.com' }, { text: 'Google', value: 'www.google.com' }, { text: 'Taobao', value: 'www.taobao.com' } ] } } }
Vue.createApp(app).mount('#app') </script>
|
值绑定:
修饰符:
.lazy
:在change事件中更新而不是在input事件中更新。
1
| <input v-model.lazy="msg">
|
.number
:转化为Number类型。
.trim
:过滤输入的首尾空格。
1
| <input v-model.trim="msg">
|
自定义指令
Vue允许注册自定义指令。
注册一个自定义的全局指令 v-focus
,功能是页面加载时元素获得焦点:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <div id="app"> <p>页面载入时,input 元素自动获取焦点:</p> <input v-focus> </div>
<script> const app = Vue.createApp({}) app.directive('focus', { mounted(el) { el.focus() } }) app.mount('#app') </script>
|
还可以在实例中directives注册局部指令:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <div id="app"> <p>页面载入时,input 元素自动获取焦点:</p> <input v-focus> </div>
<script> const app = { data() { return {} }, directives: { focus: { mounted(el) { el.focus() } } } }
Vue.createApp(app).mount('#app')
|
钩子函数
指令定义函数提供了几个钩子函数(可选):
- created : 在绑定元素的属性或事件监听器被应用之前调用。
- beforeMount : 指令第一次绑定到元素并且在挂载父组件之前调用。。
- mounted : 在绑定元素的父组件被挂载后调用。。
- beforeUpdate: 在更新包含组件的 VNode 之前调用。。
- updated: 在包含组件的 VNode 及其子组件的 VNode 更新后调用。
- beforeUnmount: 当指令与元素解除绑定且父组件已卸载时,只调用一次。
- unmounted: 当指令与元素解除绑定且父组件已卸载时,只调用一次。
实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import { createApp } from 'vue' const app = createApp({})
app.directive('my-directive', { created() {}, beforeMount() {}, mounted() {}, beforeUpdate() {}, updated() {}, beforeUnmount() {}, unmounted() {} })
app.directive('my-directive', () => { })
const myDirective = app.directive('my-directive')
|
钩子函数参数
- el: 绑定到的元素
- binding: 一个对象,包含
instance
, value
, oldValue
, arg
, modifiers
, dir
。
- vnode
- prevNode
路由
路由允许我们通过不同的url访问不同的内容。
可以实现单页面多视图应用。
需要引入vue-router。
引入
- 引入文件: https://unpkg.com/vue-router@4.0.5/dist/vue-router.global.js
- npm安装:
cnpm install vue-router@4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <script src="https://unpkg.com/vue@3"></script> <script src="https://unpkg.com/vue-router@4"></script>
<div id="app"> <h1>Hello App!</h1> <p> <router-link to="/">Go to Home</router-link> <router-link to="/about">Go to About</router-link> </p> <router-view></router-view> </div>
|
router-view将显示与url对应的组件。你可以把它放在任何地方,以适应你的布局。
混入
混入(mixins)定义了一部分可复用的方法或者计算属性。
实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| const myMixin = { created() { this.hello() }, methods: { hello() { console.log('欢迎来到混入实例-baidu!') } } }
const app = Vue.createApp({ mixins: [myMixin] })
app.mount('#app')
|
axios
axios是一个基于 Promise
的http库。
可用于浏览器和node。
安装:
- 直接引入文件。
- npm:
cnpm install axios -S
使用:
1 2 3 4 5 6 7 8 9 10 11
| Vue.axios.get(api).then((response) => { console.log(response.data); })
this.axios.get(api).then((response) => { console.log(response.data); })
this.$http.get(api).then((response) => { console.log(response.data); })
|
GET
读取JSON1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| const app = { data() {
return { info: 'Ajax 测试!!' }
}, mounted () {
axios .get('https://www.baidu.com/try/ajax/json_demo.json') .then(response => (this.info = response)) .catch(function (error) { console.log(error); });
} } Vue.createApp(app).mount('#app')
|
GET传参:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| axios.get('/user?ID=12345') .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); });
axios.get('/user', { params: { ID: 12345 } }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); });
|
POST
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| new Vue({ el: '#app', data() { return { info: null } }, mounted() { axios .post('https://www.baidu.com/try/ajax/demo_axios_post.php') .then(response => (this.info = response)) .catch(function(error) { console.log(error); }); } })
|
POST传参:
1 2 3 4 5 6 7 8 9 10
| axios.post('/user', { firstName: 'Fred', lastName: 'Flintstone' }) .then(function(response) { console.log(response); }) .catch(function(error) { console.log(error); });
|
执行多个并发请求
1 2 3 4 5 6 7 8 9 10 11
| function getUserAccount() { return axios.get('/user/12345'); }
function getUserPermissions() { return axios.get('/user/12345/permissions'); } axios.all([getUserAccount(), getUserPermissions()]) .then(axios.spread(function(acct, perms) { }));
|
axios API
可以通过向axios传递配置来创建请求:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| axios(config)
axios({ method: 'post', url: '/user/12345', data: { firstName: 'Fred', lastName: 'Flintstone' } });
axios({ method: 'get', url: 'http://bit.ly/2mTM3nY', responseType: 'stream' }) .then(function(response) { response.data.pipe(fs.createWriteStream('ada_lovelace.jpg')) }); axios(url[, config])
axios('/user/12345');
|
请求方法的别名:
1 2 3 4 5 6 7
| axios.request(config) axios.get(url[, config]) axios.delete(url[, config]) axios.head(url[, config]) axios.post(url[, data[, config]]) axios.put(url[, data[, config]]) axios.patch(url[, data[, config]])
|
在使用别名方法时, url、method、data 这些属性都不必在配置中指定。
并发:
1 2
| axios.all(iterable) axios.spread(callback)
|
创建实例:
1 2 3 4 5 6 7 8
| axios.create([config]) const instance = axios.create({ baseURL: 'https://some-domain.com/api/', timeout: 1000, headers: { 'X-Custom-Header': 'foobar' } });
|
实例方法:
1 2 3 4 5 6 7
| axios #request(config) axios #get(url[, config]) axios #delete(url[, config]) axios #head(url[, config]) axios #post(url[, data[, config]]) axios #put(url[, data[, config]]) axios #patch(url[, data[, config]])
|
拦截器
在请求被 then
或者 catch
处理之前拦截。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| axios.interceptors.request.use(function(config) { return config; }, function(error) { return Promise.reject(error); });
axios.interceptors.response.use(function(response) { return response; }, function(error) { return Promise.reject(error); });
|
移除拦截器:
1 2 3 4
| var myInterceptor = axios.interceptors.request.use(function() { }); axios.interceptors.request.eject(myInterceptor);
|
常用钩子函数
toRefs
当使用reactive
创建一个响应式对象后,如果想解构这个对象的属性,可能会失去这些属性的响应性。为了避免这种情况,可以使用toRefs
。
toRefs
可以用来解构响应式的对象,并且可以让解构出来的变量保持响应式。
1 2 3 4 5 6 7 8 9
| import { reactive, toRefs } from 'vue'
let info = reactive({ name: 'Mason', age: 22, gender: 'male', })
let { name, age, gender } = toRefs(info)
|
调试
使用浏览器调试vue。
浏览器安装vue.js devtools插件
vue开启配置
main.js
添加:
main.js1
| Vue.config.devtools = true
|
ref
- https://v3.cn.vuejs.org/guide/introduction.html
- 《Vue 3.0从入门到精通》