vue笔记3
过滤器 filters
- 基本语法:过滤器可以用在两个地方:双花括号插值和
v-bind
表达式
<div id="app">
<h1>{{money|showMoney}}</h1>
<h2>{{msg|toupper}}</h2>
<input type="text" :value="msg|toFirstupper">
</div>
<script>
new Vue({
el: "#app",
data: {
money: 243.565,
msg: "hello,vue",
},
filters: {
showMoney(data) {
console.log(data);
return data.toFixed(2)
// 保留两位小数
},
toupper: function (value) {
return value.toUpperCase();
// 将hello,vue转换成大写
},
toFirstupper(str){
return str.charAt(0).toUpperCase()+str.substr(1)
// 将hello,vue的首字母大写
}
}
})
</script>
计算属性
- 对于复杂的逻辑,应该使用计算属性来实现
- 计算属性会把结果缓存起来直接使用,只有当data中使用到的数据发生改变,才会重新计算结果
例如需要将data中的数据翻转的例子
<div id="app">
<p>{{reverseMsg}}</p>
</div>
<script>
new Vue({
el: "#app",
data: {
msg: "Hello,vue,js"
},
computed:{
reverseMsg(){
return this.msg.split('').reverse('').join('')
}
}
})
/* 具体方法的实现
msg.split('')
["H", "e", "l", "l", "o", ",", "v", "u", "e", ",", "j", "s"]将字符串分割成数组
msg.split('').reverse()
["H", "e", "l", "l", "o", ",", "v", "u", "e", ",", "j", "s"]将数组组翻转
msg.split('').reverse().join('')
sj,euv,olleH 数组转换成字符串
*/
</script>
计算属性和方法的区别
-
计算属会把计算值使用的data中变量计算的结果进行缓存,如果被计算的变量没有改变,计算属性会执行
-
方法是页面只有重新绘制,就会再次调用,一般方法是在绑定事件或副作用函数中调用
属性监听器
-
一般不需要监听
-
检测某一属性是否在改变,告诉后端这一属性在改变
<div id="app"> <p>{{money}}</p> <button @click="changes">changes</button> </div>
<script> new Vue({ el:"#app", data:{ money:20010, }, methods:{ changes(){ this.money-=1 }, }, watch:{ money(){ if(this.money<20000){ alert("资金发生异常") } } } }) </script>
vue中的data和方法同名问题
- data和methods同名问题
data和methods中的成员可以同名,但是尽量避免
因为vue对象在创建的过程中会先初始化methods中的成员然后才初始化data中的成员
一个对象不能有相同的成员 ,如果有相同成员的话后写的会覆盖先写的
<div id="app">
<p>{{age}}</p>
</div>
<script>
new Vue({
el: "#app",
data: {
age: 18
},
methods: {
age() {
return 28
}
}
})
</script>
- data和filters同名问题
因为过滤器中的成员不会直接绑定到vm对象中,所以不会跟data和方法产生同名冲突 而且过滤使用的语法是一种特殊的标记 |
所以过滤可以和data或者方法中的成员同名
<div id="app">
<p>{{11|age}}</p>
</div>
<script>
new Vue({
el: "#app",
data: {
age: 18
},
filters:{
age(){
return 49
}
}
})
</script>
-
watch
必须跟data中的成员同名 才能监听对应的成员
<div id='app'> <p>{{obj.name}}</p> <button type="button" @click="chaneg1">change1</button> </div>
<script> new Vue({ el: '#app', data: { obj:{name:"karen"} }, methods:{ chaneg1(){ this.obj.name="jack" } }, watch:{ obj(){ console.log("名字发生改变"); } } }) </script>
data中数组改变的理解?
-
因为vue在做数据劫持时 只劫持了对象和对象中的对象成员名和数组的方法 没有劫持数组的下标
-
因此通过下标的方式改变data数组源中数组中的数组改变了内存中的数据会修改,页面不会刷新,如下列的这个例子
<div id='app'>
<p>{{arr[0]}}</p>
<p>{{obj.age}}</p>
<button type="button" @click="change1">change1</button>
<button type="button" @click="look">look</button>
</div>
<script>
new Vue({
el: '#app',
data: {
arr:[10,22,33,11],
obj:{age:20}
},
methods:{
change1(){
console.log(111111111)
},
look(){
console.log(this.arr[0])
}
}
})
</script>
如果通过调用数组的方法来修改数组,页面会刷新
- 解决办法:
- 对数组全量替换(深拷贝、JSON.xx)
- 官方的静态函数Vue.set(数组名,下标,新值)
生命周期函数
生命周期函数,也叫 “钩子函数”,就是Vue实例在某一个时间点会自动执行的函数,以下有8个主要的生命周期函数
<div id="app">
<p>{{msg}}</p>
<button @click="changes">点击改变</button>
</div>
<script>
new Vue({
el: "#app",
data: {
msg: "hello,vue"
},
methods: {
changes() {
this.msg = "改变了"
},
},
beforeCreate() {
console.log("vm 对象在实例化之前调用", this.msg);
//不能操作VM功能
// 这个函数能做网络请求,但是请求的数据不能操作数据源,但是可以做预加载
// 如字体库,抢红包等功能
},
created() {
console.log("vm 对象在实例化完毕调用");
// vm对象创建完毕,可以使用VM对象中的功能
// 但是不能操作DOM
// 如果希望网络请求加载的数据一下给用户呈现,就在这里请求页面的数据
},
beforeMount() {
console.log("虚拟节点树挂载到真实文档树之前");
},
mounted() {
console.log("虚拟节点树已经挂载到真实文档树");
//已经挂载了这时候既能操作vm也能操作页面关键是这个函数调用时页面已经显示了
// ajax请求在这里面发生,可以保证先给用户显示一个页面结构,
// 然后再网络请求把页面刷新到页面的局部区域
},
beforeUpdate() {
console.log("数据更新之前", this.msg);
// debugger 卡住页面
// data初始化不会执行更新钩子
// this.msg是新改变的值,但是页面还没刷新时就会调用
},
updated() {
console.log("页面已经更新了");
},
beforeDestroy() {
console.log("vm销毁之前", this.msg);
// 最后能够访问VM的函数
// 保存用户的配置信息
},
destroyed() {
console.log("已经销毁的", this.msg);
// 无法操作VM
// 可以清理计时器等不会自动销毁的东西
// 断开网络请求
}
})
</script>
关于钩子函数的几个面试题
- 页面第一次渲染有哪些钩子执行 ?顺序是什么?
答:beforeCreate created beforeMount mounted
-
哪些钩子能做网络请求 哪些能请求页面数据
答: 所有钩子都能
但是操作vm的话 就必须在 created beforeMount mounted
updata/beforeUpdate 可以访问vm,但是不能请求数据用于显示 因为会造成循环
beforeDestroy
-
DOM 渲染在 哪个周期中就已经完成
答:mounted
自定义函数
vue项目中会用到一些自定义的函数,在directives里面可以定义自己的自定义函数,如以下例子:
<div id="app">
<p v-pink>hhh</p>
<!-- 当前节点插入到父节点时调用自定义属性 pink -->
<p v-pink></p>
<input type="text" v-focus>
<!-- 输入框会闪烁 -->
<p v-msg="msg" v-link="'https://www.baidu.com/index.html'"></p>
<!-- v-msg 将数据传递到某一节点上
v-link 点击跳转到另外一个页面
-->
</div>
<script>
new Vue({
el: "#app",
data: {
msg: "hello,vue"
},
directives: {
pink: {
inserted(a, b) {
a.style.color = "red"
console.log(a, b);
}
},
focus: {
inserted(a) {
a.focus()
}
},
msg: {
inserted(a, b) {
console.log(a, b);
a.innerHTML = b.value
}
},
link:{
inserted(a,b){
a.onclick=()=>{
window.location.href=b.value
}
}
}
}
})
</script>
组件
组件分为全局组件和自定义组件
全局组件:
- 组件的属性不能用大写字母
- 组件的名字可以用驼峰命名法,但是使用的时候必须用连字符
- 全局注册的组件使用时不能使用单标签(不会报错,但是只能使用一次 多次使用只显示第一个)
- 注册的组件不要跟系统标签同名
局部组件:
- 一个vm实例可以有多个局部组件,但是只能供当前vm实例使用
<div id="app">
<my-brother></my-brother>
<baidu></baidu>
<all></all>
</div>
<script>
Vue.component("all",{
template:`
<p>我是自定义全局组件</p>
`
})
new Vue({
el: "#app",
data: {
msg: "vue"
},
components:{
myBrother:{
template:`
<div> myBrother</div>
},
baidu:{
data(){
return {data:"我是与myBrother同一级的百度"}
},
template:`
<div>
<h1>{{data}}</h1>
</div>
`,
components:{
son:{
template:`
<p>我是全局变量的all</p>
`
}
}
}
},
})
</script>