1. 双向数据绑定
input框中的文字可以即时显示在<h1>标签中:
<div id="app">
<input type="text" :value="str" @input="change">
<h1>{{str}}</h1>
</div>
<script src="./node_modules/vue/dist/vue.min.js"></script>
<script>
new Vue({
el: "#app",
data: {
str: '我爱Vue'
},
methods: {
change: function (e) {
let event = e || event;
this.str = event.target.value
}
}
})
</script>
v-model就类似于上面的写法,是一种语法糖,来实现双向数据绑定。
@keyup后面可以接修饰符 .enter .keyCode值 ,
当按下回车键时,alert 出 input框中的文字:
<div id="app">
<input type="text" v-model="str" @keyup.13="keyFn">
<h1>{{str}}</h1>
</div>
<script src="./node_modules/vue/dist/vue.min.js"></script>
<script>
new Vue({
el: "#app",
data: {
str: '我爱Vue'
},
methods: {
keyFn(e) {
alert(this.str)
}
}
})
</script>
2. v-if 与 v-show 的区别
<h1 v-if="false">pineapple</h1>
v-if 的元素只会在指令的表达式返回 true 时被渲染。如返回 false ,在DOM文档中找不到对应的元素,变成了注释。
<span v-show="false">apple</span>
v-show 的元素始终会被渲染并保留在 DOM 中。 只是简单地基于 CSS display进行切换。
v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。
因此,如果需要非常频繁地切换,则使用 v-show 较好;
如果在运行时条件很少改变(例如页面一开始加载的时候进行判断显示),则使用 v-if 较好。
在实际的开发过程中,使用v-if比较多。
3. v-if 与 v-for 一起使用
不推荐同时使用 v-if 和 v-for。
当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级。
<div id="app">
<ul>
<!-- <li v-for="(item,index) in list" v-if="item>1"> -->
//不推荐上面的写法
<li v-for="(item,index) in list">
<span v-if="item>1">
{{item}}
</span>
</li>
</ul>
</div>
<script src="./node_modules/vue/dist/vue.min.js"></script>
<script>
new Vue({
el: "#app",
data: {
list: [1, 2, 3]
}
})
</script>
❤️解决思路:使用computed计算属性来过滤数据,之后再渲染过滤好的的数据。
<div id="app">
<ul>
<li v-for="(item,index) in arr">
{{item}}
</li>
</ul>
</div>
<script src="./node_modules/vue/dist/vue.min.js"></script>
<script>
new Vue({
el: "#app",
data: {
list: [1, 2, 3]
},
computed: {
arr: function () {
return this.list.filter(r => r > 1)
}
}
})
</script>
4. 监听器 watch
监听器watch, 只要data中的值被改变了就会被触发。
基本数据类型可以使用简写的方式。
引用数据类型使用简写的方式无效,需改用对象的方式,加deep:true深度监听。
<div id="app">
<h1>¥{{price}}</h1>
<button @click="up">涨价10元</button>
<h1>¥{{car.price}}w</h1>
<button @click="carUp">涨价1w</button>
<h2>您的爱车相比原价涨了{{car.expensive}}w</h2>
</div>
<script src="./node_modules/vue/dist/vue.min.js"></script>
<script>
new Vue({
el: "#app",
data: {
price: 100,
car: {
price: 100,
price0: 100,
expensive: 0
}
},
watch: {
/*属性需要和data中的属性相对应 */
/* 第一个参数a表示最新的值 第二个参数b表示之前的值 */
price: function (a, b) {
console.log('相比原价贵了' + (a - 100) + '元');
},
car: {
// 进入页面会立即执行监听器里面的handler方法
immediate: true,
// 深度监听
deep: true,
//handler方法名是固定的不可以被篡改
handler: function () {
this.car.expensive = this.car.price - this.car.price0
}
}
},
methods: {
carUp: function () { this.car.price++ },
up: function () {
this.price = this.price + 10
}
}
})
</script>
5. 周期函数/钩子函数
<div id="app">
<h1>{{msg}}</h1>
<button @click="change">改变msg</button>
<button @click="destroy">销毁Vue实例</button>
<h1>{{time}}</h1>
</div>
<script src="./node_modules/vue/dist/vue.min.js"></script>
<script>
/* Vue的八大生命周期钩子函数 */
/* 区别之一:执行顺序的问题 beforeCreate>created>beforeMount>mounted */
new Vue({
el: "#app",
data: {
msg: '我爱Vue',
time: 0,
timeId: null
},
/* Vue实例化对象创建之前 */
beforeCreate() {
/* 实例化对象创建之前是获取不到data里面的数据的 */
console.log('beforeCreate', this.msg)
},
/* Vue实例化对象创建之后 */
created() {
/* 实例化对象创建之后可以获取data里面的数据 */
/* 实例化对象创建之后不可以获取到dom包括根节点 */
console.log('created', this.msg, this.$el)
/* ★一般在created里面调用接口把接口里面的数据赋值给到Vue的data中 */
this.timeId = setInterval(() => {
this.time++;
console.log(this.time)
}, 500)
},
/* Vue的dom挂载之前 */
beforeMount() {
/* dom挂载之前可以获取到根节点 */
/* beforeMount还没有把data中的数据渲染到dom节点上 */
console.log('beforeMount', this.$el)
},
/* Vue的dom挂载之后 */
mounted() {
/* mounted已经把data中的数据渲染到了dom节点上 */
console.log('mounted', this.$el)
/* ★一般在获取dom节点操作要放在mounted中执行,例如echarts中获取根元素 */
},
/* Vue的data值更新前 */
/* 当我把Vue实例中的data中的值改变了会触发beforeUpdate和updated */
/* 顺序上 beforeUpdate执行顺序优先于updated */
beforeUpdate() {
console.log('beforeUpdate', this.msg, this.$el)
},
/* Vue的data值更新后 */
updated() {
console.log('updated', this.msg, this.$el)
},
/* Vue组件销毁前 */
/* 在调用$destroy()方法的时候 会执行下面的两个钩子函数 */
/* 执行顺序上beforeDestroy优先于destroyed执行 */
/* ★beforeDestroy和destroyed的一个使用场景是在销毁定时器节约内存的时候都可以使用 */
beforeDestroy() {
console.log('beforeDestroy', this.msg, this.$el)
},
/* Vue组件销毁后 */
destroyed() {
console.log('destroyed', this.msg, this.$el)
clearInterval(this.timeId)
},
methods: {
change() {
this.msg = '我爱React'
},
destroy() {
this.$destroy();
}
}
})
</script>
6. 自定义指令
<div id="app">
<input type="text" v-focus="{background:'yellow'}">
<p
v-fontsize="{fontSize:'50px'}"
v-sty="{background:'red',color:'yellow'}">hello</p>
</div>
<script src="./vue.min.js"></script>
<script>
/* 全局自定义指令 全面的写法 */
Vue.directive('focus', {
/* 当绑定元素插入到 DOM 中 */
inserted: function (el, binding) {
console.log(binding)
el.focus();
el.style.background = binding.value.background;
}
})
new Vue({
el: "#app",
/* 局部的自定义指令 */
directives: {
fontsize: {
inserted: function (el, binding) {
console.log(binding)
el.style.fontSize = binding.value.fontSize;
}
},
sty(el, binding) {
el.style.color = binding.value.color;
el.style.background = binding.value.background;
}
}
})
</script>
7. 过滤器+渲染优化
<head>
<style>
[v-cloak] {
display: none;
}
</style>
</head>
<body>
<!-- 使用v-属性 style设置display:none 实现渲染优化 -->
<div id="app" v-cloak>
<!-- | 过滤器的管道符 -->
<h1>{{'春如四季'|fn('天气')|fn('多变')}}</h1>
<h1>{{'宝贝'|str('快逃')}}</h1>
<h1>{{msg|dao}}</h1>
</div>
<script src="./vue.min.js"></script>
<script>
/* 全局过滤器 */
Vue.filter('fn', function (v, s) {
/* v就是管道符左边的数据 s为传过来的参数*/
return v + s;
})
new Vue({
el: "#app",
data: {
msg: 'hello'
},
/* 局部过滤器 */
filters: {
str: function (v, s) {
return v + s;
},
//字符串倒序
dao: function (v) {
return v.split('').reverse().join('')
}
}
})
</script>
</body>
8. 组件
| 组件 | |
|---|---|
| 概念 | 组件即自定义控件 |
| 用途 | 组件能够封装可重用代码,扩展HTML标签功能 |
| 本质 | 自定义标签 |
| 分类 | 全局组件:不同作用域内均可使用 局部组件:只在定义该组件的作用域内可以使用 |
❗注意:组件和Vue实例类似,需要注册后才可以使用。
<body>
<div id="app">
<!-- 组件名中含有大写字母,浏览器编译的时候会转成小写,导致找不到相应的组件,
可以全变成小写,中间加-来解决 -->
<!-- 所有的组件都需要使用一个div来包裹 -->
<div>
<child-b />
</div>
<div>
<son />
</div>
</div>
<!-- 模板的第二种写法 使用template加id -->
<template id="ChildB">
<!-- template里面也需要使用div来包裹一下 -->
<div>
<h1>我是ChildB</h1>
<h1>我是ChildB</h1>
<div>
<child-a />
</div>
</div>
</template>
<script src="./node_modules/vue/dist/vue.min.js"></script>
<script>
/* 一定要写在new Vue的前面 */
/* 全局组件 */
Vue.component('ChildA', {
/* 模板的第一种写法 直接写 */
template: '<h1>我是ChildA</h1>',
created: function () {
console.log('我是childA')
}
})
Vue.component('ChildB', {
template: '#ChildB'
})
new Vue({
el: "#app",
//局部组件
components: {
son: {
template: `<h1>我是局部组件son</h1>`,
created() {
console.log('son')
}
}
}
})
</script>
9. 父子组件传值
子改父的步骤
①使用Vue里面的$emit方法发送一个自定义事件,如childchange
②在父组件上使用@childchange="ctrl" 绑定自定义事件,触发父组件的ctrl方法
③在父组件中的ctrl方法内把父组件的对应的值给改了
<!-- 父组件有个一个数组对象 传值给子组件展示
点击子组件里面的某一项 可以把父组件里面的数组的某一项给删除 -->
<div id="box">
<kid :list='list' @delkid='del' />
</div>
<template id="kid">
<div>
<ul>
<li v-for="(item,index) in list" :key="index" @click="del(index)">{{item.content}}</li>
</ul>
</div>
</template>
<script src="./node_modules/vue/dist/vue.min.js"></script>
<script>
new Vue({
el: '#box',
data: {
list: [{ content: 'apple' }, { content: 'pineapple' }, { content: 'applepie' }]
},
methods: {
del(index) {
this.list.splice(index, 1)
}
},
components: {
kid: {
template: '#kid',
props: ['list'],
methods: {
del(index) {
this.$emit('delkid', index)
}
},
}
}
})
</script>
10. 插槽
(1)
<div id="app">
<child-a>
<h1 slot="gy1">我爱美丽的小公园1</h1>
<h1 slot="gy2">我爱美丽的小公园2</h1>
</child-a>
</div>
<template id="childA">
<div>
<!-- 匿名插槽 <slot></slot> -->
<!-- 具名插槽 -->
<slot name="gy1"></slot>
<h1>我是childA</h1>
<slot name="gy2"></slot>
</div>
</template>
<script src="./vue.js"></script>
<script>
new Vue({
el: "#app",
/* 注册组件的命名是首字母大写 使用组件的时候中间要使用-分割 */
components: {
ChildA: {
template: "#childA"
}
}
})
</script>
(2) 作用域插槽
11. 数据变化且触发视图更新
(1)添加数据this.$set()
<div id="app">
<h1>{{list}}</h1>
<button @click="fn">添加age</button>
<hr>
<h1>{{arr}}</h1>
<button @click="fn2">添加car</button>
</div>
<script src="./vue.min.js"></script>
<script>
new Vue({
el: "#app",
data: {
list: {
name: 'tom'
},
arr: [{
name: 'jack'
}, {
name: 'taotao'
}]
},
methods: {
fn() {
/* Vue2的一个缺陷不可以给对象添加新属性
解决这个bug的方案是 使用$set*/
/* this.$set(目标对象,具体的key要使用引号,具体的值) */
this.$set(this.list, 'age', 30)
console.log(this.list)
},
fn2() {
/* 这是更新对象数据的方式 */
// this.$set(this.arr[1],'car','bmw')
/* 这个更新数组的到视图的方式 */
/* 三个参数分别对应 目标数组 数组所在的索引 和需要修改的内容 */
this.$set(this.arr, 1, { name: 'taotao', car: 'benchi' })
}
}
})
</script>
(2)删除数据this.$delete()
(3)强制刷新this.$forceUpdate()
<div id="app">
<!-- <h1>{{obj}}</h1>
<button @click="fn1">添加age</button>
<button @click="fn2">删除age</button> -->
<!-- <h1>{{list}}</h1>
<button @click="add">添加benchi</button> -->
<ul>
<li v-for="(v,i) in arr" :key="i" @click="del(i)">{{v}}</li>
</ul>
<button @click="addAge">添加age</button>
</div>
<script src="./vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
obj: {
name: '张三'
},
list: [{
car: 'bmw',
}],
arr: [{ name: 'zhangsan' }, { name: 'lisi' }]
},
methods: {
fn1() {
/* 第一种值和视图都改变的方式 */
// this.$set(this.obj,'age',30)
/* 第二个种更直接更暴力的渲染视图的方式 */
this.obj.age = 30;
this.$forceUpdate();
},
fn2() {
/* 第一种删除对象里面的属性更新视图的方式 */
// delete this.obj.age;
// this.$forceUpdate();
/* 第二种删除对象里面的属性并更新视图的方式 */
/* $delete 第一个参数是 目标对象 第二个参数是 具体的key
要使用字符串*/
this.$delete(this.obj, 'age')
console.log(this.obj)
},
add() {
/* 第一种方式 */
// this.$set(this.list,0,{car:this.list[0].car,car2:'benchi'})
this.$set(this.list[0], 'car2', 'benchi')
/* 第二种方式 */
// this.list[0].car2 = 'benchi'
// this.$forceUpdate();
console.log(this.list)
},
addAge() {
// this.arr.forEach(r=>{
// r.age = 30;
// })
// this.$forceUpdate();
this.arr.forEach(r => {
this.$set(r, 'age', 30)
})
},
del(i) {
/* 删除对象的某一个属性 */
// this.$delete(this.arr[i],'name')
// delete this.arr[i].name;
// this.$forceUpdate();
/* 删除数组的一个对象 */
this.arr.splice(i, 1);
this.$forceUpdate();
// this.$delete(this.arr,i)
}
}
})
</script>