Vue笔记
文章目录
Vue的指令
- v-for 循环
<li v-for="item in list">{{ item }}</li>
<!-- 循环 list,将list里面的每一项赋值给 item -->
- v-on 事件绑定 (执行事件的函数要写在 Vue 实例中的 methods 中,简写@,如:@click)
<button v-on:click="handleBtnClick">提交</button>
<!-- handleBtnClick 方法要写在 Vue 实例的 methods 中 -->
- v-model 在表单控件或者组件上创建双向绑定
<input type="text" v-model="inputValue" />
<!-- inputValue 是 Vue 实例中 data 里的值 -->
- v-bind 数据绑定 (简写直接冒号)
<todo-item v-bind:content="item" v-for="item in list"></todo-ittem>
<!-- 父组件循环 list,将 list 的每一项赋给 item,然后子组件将 item 的值赋给 content -->
例子1:简单的 todolist
<div id="app">
<input type="text" v-model="inputValue" />
<button v-on:click="handleBtnClick">提交</button>
<ul>
<li v-for="item in list">{{ item }}</li>
</ul>
</div>
<script>
const app = new Vue({
el: '#app',
data: {
list: [],
inputValue: ''
},
methods: {
handleBtnClick: function () {
this.list.push(this.inputValue)
this.inputValue = ''
}
}
})
</script>
例子2: todolist组件化——全局组件
<div id="app">
<input type="text" v-model="inputValue" />
<button v-on:click="handleBtnClick">提交</button>
<ul>
<!-- <li v-for="item in list">{{ item }}</li> -->
<todo-item v-bind:content="item" v-for="item in list"></todo-ittem>
</ul>
</div>
<script>
// 全局组件
Vue.component('TodoItem', {
props: ['content'],
template: `<li>{{content}}</li>`
})
const app = new Vue({
el: '#app',
data: {
list: [],
inputValue: ''
},
methods: {
handleBtnClick: function () {
this.list.push(this.inputValue)
this.inputValue = ''
}
}
})
</script>
例子3: todolist组件化——局部组件
<div id="app">
<input type="text" v-model="inputValue" />
<button v-on:click="handleBtnClick">提交</button>
<ul>
<!-- <li v-for="item in list">{{ item }}</li> -->
<todo-item v-bind:content="item" v-for="item in list"></todo-ittem>
</ul>
</div>
<script>
// 局部组件
const TodoItem = {
props: ['content'],
template: `<li>{{content}}</li>`
}
const app = new Vue({
el: '#app',
components: {
TodoItem
},
data: {
list: [],
inputValue: ''
},
methods: {
handleBtnClick: function () {
this.list.push(this.inputValue)
this.inputValue = ''
}
}
})
</script>
例子3: todolist组件化——父子组件的相互传值
子组件可以通过 $emit
向外触发事件
<div id="app">
<input type="text" v-model="inputValue" />
<button v-on:click="handleBtnClick">提交</button>
<ul>
<!-- <li v-for="item in list">{{ item }}</li> -->
<todo-item v-bind:content="item"
v-for="(item, index) in list"
@delete="handleItemDelete"
v-bind:index="index"
></todo-ittem>
</ul>
</div>
<script>
// 局部组件
const TodoItem = {
props: ['content', 'index'],
template: `<li @click='handleItemClick'>{{content}}</li>`,
methods: {
handleItemClick: function() {
this.$emit('delete', this.index)
// $emit 向外触发事件
}
}
}
const app = new Vue({
el: '#app',
components: {
TodoItem
},
data: {
list: [],
inputValue: ''
},
methods: {
handleBtnClick: function () {
this.list.push(this.inputValue)
this.inputValue = ''
},
handleItemDelete: function (index) {
this.list.splice(index, 1)
}
}
})
</script>
vue 的生命周期函数
<div id="app"></div>
<script>
const vm = new Vue({
el: '#app',
template: `<div>{{ test }}</div>`,
data: {
test: 'hello world'
},
beforeCreate() {
console.log('beforeCreate')
},
created() {
console.log('created')
},
beforeMount() {
console.log('beforeMount')
},
mounted() {
console.log('mounted')
},
beforeDestroy() {
console.log('beforeDestroy')
},
destroyed() {
console.log('destroyed')
},
beforeUpdate() {
console.log('beforeUpdate')
},
updated() {
console.log('updated')
},
})
</script>
计算属性,方法和监听器
| 如果某个功能可以用 计算属性,方法和监听器 三种方式实现,优先选择计算属性
- 计算属性
计算属性内置缓存,没有改变计算需要用到的变量的值时,就不会重新计算
<div id="app">
{{ fullName }}
{{ age }}
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
firstName: 'Xianggang',
lastName: 'Diao',
age: 21
},
computed: { // 计算属性(内置缓存)
fullName() {
console.log('计算了一次') // 没有用到 age,即便修改age的值,也不会重新计算,只有修改 firstName和lastName的时候,才会重新计算
return `${this.firstName} ${this.lastName}`
},
}
})
</script>
- 方法(计算属性的方法实现)
没有内置缓存,改变任意值都会重新计算
<div id="app">
{{ fullName() }} <!-- 调用方法,加括号 -->
{{ age }}
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
firstName: 'Xianggang',
lastName: 'Diao',
age: 21
},
methods: {
fullName(){
console.log('计算了一次')
return `${this.firstName} ${this.lastName}`
}
}
})
</script>
- 监听器
<div id="app">
{{ fullName }}
{{ age }}
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
firstName: 'Xianggang',
lastName: 'Diao',
fullName: 'Xianggang Diao',
age: 21
},
watch: {
// 监听 firstName 和 lastName, 一旦firstName 和 lastName改变,就重新计算fullName
firstName() {
console.log('计算了一次')
this.fullName = `${this.firstName} ${this.lastName}`
},
lastName() {
console.log('计算了一次')
this.fullName = `${this.firstName} ${this.lastName}`
}
}
})
</script>
计算属性的 getter 和 setter
<div id="app">
{{ fullName }}
{{ age }}
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
firstName: 'Xianggang',
lastName: 'Diao',
age: 21
},
computed: {
fullName: {
get() {
return `${this.firstName} ${this.lastName}`
},
set(value) {
console.log(value)
const arr = value.split(' ')
this.firstName = arr[0]
this.lastName = arr[1]
}
},
}
})
</script>
Vue的条件渲染
在 Vue 中通过 v-if
和 v-show
可以控制元素是否显示,他们的区别是:v-if
的条件为 false
时,DOM 根本不会渲染元素,及根本不存在此元素,v-show
的条件是 false
时,只是将它CSS设成了 display: none
,因此v-show
的性能要高一些
<div id="app">
<div v-if="show">{{ message }}</div>
<div v-show="show">{{ message }}</div>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
show: false,
message: 'hello World'
}
})
</script>
v-if
和 v-else
指令的使用
<div id="app">
<div v-if="show">{{ message }}</div>
<div v-else>Bye World</div>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
show: false,
message: 'hello World'
}
})
</script>
注意 v-if 和 v-else 之间不能有标签
错误举例
<div id="app">
<div v-if="show">{{ message }}</div>
<div>v-if 和 v-else 之间不能有标签,会报错</div>
<div v-else>Bye World</div>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
show: false,
message: 'hello World'
}
})
</script>
连写多个 v-if
和 v-else-if
<div id="app">
<div v-if="show === 'a'">This is a</div>
<div v-else-if="show === 'b'">This is b</div>
<div v-else>This is others</div>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
show: 'a',
}
})
</script>
Vue 数组的注意事项
在 Vue 中使用数组时要注意,不要用更改数组具体的某一项来改变数组,如:list[0] = 'hello'
,因为 Vue 会将数组的某一项进行封装,实际使用的不再是你定义时的东西了,数组的每一项都是一个 Vue 封装的对象。
想要修改数组的某一项时,要使用 Vue 提供的方法 pop
, splice
, shift
, unshift
, sort
, push
, reserve
也可以用 set
方法改变值:
// 将数组 userInfo 中的 第二项 的值改成 5
Vue.set(vm.userInfo, 1, 5)
// 或者是
vm.$set(vm.userInfo, 1, 5)
/*
<div id="app">
<template v-for="(value, key, index) of userInfo">
<div>{{ value }} --- {{ key }}</div>
<span>{{ index }}</span>
</template>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
userInfo: {
name: 'diao',
age: '21',
sex: 'male'
}
}
})
</script>
*/
// 对对象也适用
// 给 userInfo 对象添加一条数据,键为:'address', 值为 'beijing'
Vue.set(vm.userInfo, 'address', 'beijing')
// 把 userInfo 对象中键为:'name' 的值改为 'li'
vm.$set(vm.userInfo, 'name', 'li')
Vue 的一些注意事项
h5规定在 table 标签下要有 tbody,tbody下面要有 tr,因此在某些情况下,使用Vue的组件会导致DOM结构和设想的不一致,可以使用 is
来解决
<div id="app">
<table>
<tbody>
<tr is="row"></tr>
</tbody>
</table>
</div>
<script>
Vue.component('row', {
template: `<tr><td>this is row</td></tr>`
})
const vm = new Vue({
el: '#app'
})
</script>
在 Vue 中,根组件是可以直接使用 data 对象,但是子组件不能使用 data 对象,应该使用 data方法,该方法返回一个对象来‘定义’变量
<div id="app">
<table>
<tbody>
<tr is="row"></tr>
</tbody>
</table>
</div>
<script>
Vue.component('row', {
data() {
return {
content: '不能直接使用,必须是个方法,返回对象'
}
},
template: `<tr><td>{{ content }}</td></tr>`
})
const vm = new Vue({
el: '#app',
data: {
text: '可以直接使用'
}
})
</script>
在 Vue 中获取 DOM 节点,可以使用 ref
引用来获取。$refs
可以获取全部的引用
<div id="app">
<div
ref='hello'
@click="handleClick"
>
hello world
</div>
</div>
<script>
const vm = new Vue({
el: '#app',
methods: {
handleClick() {
const el = this.$refs.hello
console.log(el.innerHtml) // hello world
}
}
})
</script>
父组件上使用 ref
获取到的是 DOM 元素,子组件上使用 ref
获取到的是子组件的引用
<div id="app">
<counter ref="one" @change="handleChange"></counter>
<counter ref="two" @change="handleChange"></counter>
<div>{{ total }}</div>
</div>
<script>
Vue.component('counter', {
template: `<div @click="handleClick">{{ number }}</div>`,
data() {
return {
number: 0
}
},
methods: {
handleClick() {
this.number ++
this.$emit('change')
}
}
})
const vm = new Vue({
el: '#app',
data: {
total: 0
},
methods: {
handleChange() {
const one = this.$refs.one.number
const two = this.$refs.two.number
this.total = one + two
}
}
})
</script>
父子组件之间的传值
- 父组件通过属性的方式向子组件传值
父组件可以向子组件传递参数,但是子组件只能使用此参数,不能修改,这是 Vue 单项数据流的概念 - 子组件通过向外触发事件,通过事件参数的方式传值
<!-- 父组件向子组件传值 -->
<div id="app">
<counter :count="0"></counter>
<counter :count="1"></counter>
</div>
<script>
const counter = {
props: ['count'],
data() {
return {
number: this.count
}
},
template: `<div @click="handleClick">{{ number }}</div>`,
methods: {
handleClick() {
this.number ++
}
}
}
const vm = new Vue({
el: '#app',
components: {
counter
}
})
</script>
<!-- 子组件向父组件传值 -->
<div id="app">
<counter :count="0" @change="handleChange"></counter>
<counter :count="1" @change="handleChange"></counter>
<div>{{ total }}</div>
</div>
<script>
const counter = {
props: ['count'],
data() {
return {
number: this.count
}
},
template: `<div @click="handleClick">{{ number }}</div>`,
methods: {
handleClick() {
this.number = this.number + 2
this.$emit('change', 2)
}
}
}
const vm = new Vue({
el: '#app',
data: {
total: 1
},
components: {
counter
},
methods: {
handleChange(step) {
this.total += step
}
}
})
</script>
参数校验
<div id="app">
<child :content="'hell'"></child>
</div>
<script>
Vue.component('child', {
props: {
content: String, // 子组件对父组件传递的参数进行校验(约束),这里要求父组件传过来的 content 必须是一个 string
test1: [String, Number], // 传的参数可以是 string 也可以是 Number,
test2: {
type: String,
required: false, // 为 true 时,参数必传
default: 'default value', // 没传参数时,显示此值
validator(value) {
return (value.length > 5) // 传递的 test2 这个参数长度必须大于5
},
}
},
template: `<div>{{ content }}</div>`
})
const vm = new Vue({
el: '#app',
})
</script>
给组件添加一个原生的事件
使用 v-on:click.native
给组件添加原生事件
<div id="app">
<child @click.native="handleClick"></child>
</div>
<script>
Vue.component('child', {
template: `<div>Child</div>`
})
const vm = new Vue({
el: '#app',
methods: {
handleClick() {
alert('click')
}
}
})
</script>
或者是使用向外触发事件
<div id="app">
<child @click="handleClick"></child>
</div>
<script>
Vue.component('child', {
template: `<div @click="handleChildClick">Child</div>`,
methods: {
handleChildClick() {
alert('child click')
this.$emit('click')
}
}
})
const vm = new Vue({
el: '#app',
methods: {
handleClick() {
alert('click')
}
}
})
</script>
运用总线模式(Bus/总线/发布订阅模式/观察者模式)在非父子组件之间传值
<div id="app">
<child content = "Xianggang"></child>
<child content = "Diao"></child>
</div>
<script>
Vue.prototype.bus = new Vue()
Vue.component('child', {
data: function(){
return {
selfContent: this.content
}
},
props: {
content: String
},
template: `<div @click = "handleClick">{{ selfContent }}</div>`,
methods: {
handleClick: function() {
this.bus.$emit('change', this.selfContent)
}
},
mounted: function() {
var _this = this
this.bus.$on('change', function (msg) {
_this.selfContent = msg
})
}
})
const vm = new Vue({
el: '#app',
methods: {
}
})
</script>
作用域插槽
固定写法:<template solt-scope=""></template>
<div id="app">
<child>
<template slot-scope="props"> <!-- slot-scope后面的随便取名 -->
<h1>{{ props.item }}</h1>
</template>
</child>
</div>
<script>
Vue.component('child', {
data: function(){
return {
list: [1, 2, 3, 4]
}
},
template: `<div>
<ul>
<slot
v-for="item of list"
:item = item
>
</slot>
</ul>
</div>`,
})
const vm = new Vue({
el: '#app'
})
</script>
动态组件
点击按钮切换组件的 v-if
实现方式
<div id="app">
<child-one
v-if="type === 'child-one'"
></child-one>
<child-two
v-if="type === 'child-two'"
></child-two>
<button @click="hadleBtnClick">change</button>
</div>
<script>
Vue.component('child-one', {
template: `<div>child one</div>`,
})
Vue.component('child-two', {
template: `<div>child two</div>`,
})
const vm = new Vue({
el: '#app',
data: {
type: 'child-one'
},
methods: {
hadleBtnClick() {
this.type = this.type === 'child-one' ? 'child-two' : 'child-one'
}
}
})
</script>
动态组件的实现方式
会根据:is
里面的类型动态加载组件,通过在组件中加入 v-once
指令,可以使组件在第二次被加载时直接从内存中读取,从而大大提高效率
<div id="app">
<!-- vue中 <component></component> 就是动态组件-->
<component :is="type"></component>
<!-- <child-one
v-if="type === 'child-one'"
></child-one>
<child-two
v-if="type === 'child-two'"
></child-two> -->
<button @click="hadleBtnClick">change</button>
</div>
<script>
Vue.component('child-one', {
template: `<div v-once>child one</div>`,
})
Vue.component('child-two', {
template: `<div v-once>child two</div>`,
})
const vm = new Vue({
el: '#app',
data: {
type: 'child-one'
},
methods: {
hadleBtnClick() {
this.type = this.type === 'child-one' ? 'child-two' : 'child-one'
}
}
})
</script>
CSS过渡效果
Vue中的过渡动画使用<transition></transition>
包裹,不管是里面的动态组件还是 v-if
或是 v-show
都可以实现,在 transition
标签中没加 name
属性时,默认是 v-enter
或是 v-leave
······,加了 name
属性后,就是 属性-enter
或是 属性-leave
······,如下面例子就是 fade-enter
<head>
<style>
.fade-enter, .fade-leave-to {
opacity: 0;
}
.fade-enter-active, .fade-leave-active {
transition: all 3s;
}
</style>
</head>
<body>
<div id="app">
<transition name="fade">
<div v-if="show">hello world</div>
</transition>
<button @click="hadleBtnClick">change</button>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
show: true
},
methods: {
hadleBtnClick() {
this.show = !this.show
}
}
})
</script>
过渡动画的自定义class
<head>
<style>
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(1);
}
}
.active {
transform-origin: left center;
animation: bounce-in 1s;
}
.leave {
transform-origin: left center;
animation: bounce-in 1s reverse;
}
</style>
</head>
<body>
<div id="app">
<transition name="fade"
enter-active-class="active"
leave-active-class="leave"
>
<div v-if="show">hello world</div>
</transition>
<button @click="hadleBtnClick">change</button>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
show: true
},
methods: {
hadleBtnClick() {
this.show = !this.show
}
}
})
</script>
JS 动画
运用 transition
标签的钩子函数实现 JS 动画
<head>
<style>
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(1);
}
}
.active {
transform-origin: left center;
animation: bounce-in 1s;
}
.leave {
transform-origin: left center;
animation: bounce-in 1s reverse;
}
</style>
</head>
<body>
<div id="app">
<transition @before-enter="handleBeforeEnter"
@enter="handleEnter"
@after-enter="handleAfterEnter"
>
<div v-if="show">hello world</div>
</transition>
<button @click="hadleBtnClick">change</button>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
show: true
},
methods: {
hadleBtnClick() {
this.show = !this.show
},
handleBeforeEnter(el) {
console.log('handleBeforeEnter')
el.style.color = 'red'
},
handleEnter(el, done){
console.log('handleEnter')
setTimeout( () => {
el.style.color = 'green'
setTimeout(done, 4000)
}, 2000)
},
handleAfterEnter(el) {
console.log('handleAfterEnter')
el.style.color = 'black'
}
}
})
</script>