Vue

  • 2021 年 12 月 26 日
  • 笔记

指令

v-for//循环 <li v-for="item in arr" >item</li>
v-click//绑定事件 可以使用简写 语法糖 @click="" 添加浏览器对象 click(123,$event)
v-once //只会修改一次 <a v-once> {{name}} </a> 不会再次跟着model的修改修改了
v-html //将字符串中的 html给解析出来 <a v-html="div"></a> 将div字符变量解析到a标签中
v-text //直接将覆盖到html 标签中 <a v-text="name"></a> 相当于 {{name}}
v-pre //和html的pre一样 原封不动的展示出来 <a>{{name}}</a> 不会解析name 直接显示 {{name}}
v-coald //加载完成之前隐藏起来 就看不到mustache代码了
v-bind //动态绑定属性 v-bind:src="src" 可以简写 :src="src" 
		动态绑定class class='title' :class="{red:true,blue:false}"title red 通过修改布尔值来决定是否需要追加此类
         :class="{red:true,blue:false}" == :class="[red,blue]"
复杂或者多条语句是就可以使用计算属性 或者 methods中
        methods:{
            color(){
                return {red:this.isred,blue:this.isblue}
            }
        }
		html:<a :class="color()">hello</a>

计算属性

和methods 的区别在与 使用时不需要加括号调用 fullanme -- fullname()
在view 和 model 不改变触发的情况下 方法是或被多次调用执行 而计算属性 只会被调用一次
computed:{
	fullname(){
		return this.firstName+this.Lastname
	}
}
<h1>{{fullname}}</h1>

上面的计算属性只是简写完整写法是:
	color:{
		get(){
			return this.name
		},
		set(newVlue){
			this.name=newVlue	
		}
	}
	由于我们使用时一般很少用到set方法 所以就可以直接用上面的方法简写

v-on 修饰符

@click.stop="aa(123)"
stop 阻止冒泡
prevent 阻止默认事件
@keyup.enter 监听回车
.native 监听组件
@click.once 只触发一次 

v-if

值为布尔 是否显示
<h1 v-if="true">真显示我</h1>
<h2 v-else>假显示我</h2>

<h2 v-if="sum==100">
 	满分
</h2>
<h2 v-else-if="sum>70">
    优秀
</h2>
<h2 v-else>
    及格
</h2>

生命周期

vue 创建销毁周期

beforeCreate(创建前)
在数据观测和初始化事件还未开始。
created(创建后)
完成数据观测,属性和方法的运算,初始化事件,$el属性还没有显示出来。
beforeMounted(挂载前)
在挂载开始之前被调用,相关的render函数首次被调用。实例已完成以下的配置:
编译模板,把data里面的数据和模板生成html。此时还没有挂载html到页面上。
mounted(挂载后)
在el被新创建的vm.$el 替换,并挂载到实例上去之后调用。实例已完成以下的配置:
用上面编译好的html内容替换el属性指向的DOM对象。完成模板中的html渲染到html页面中。此过程中进行ajax交互。
beforeUpdate(更新前)
在数据更新之前调用,发生在虚拟DOM重新渲染和打补丁之前。可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程。
updated(更新后)		
在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。调用时,组件DOM已经更新,所以可以执行依赖于DOM的操
作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用。
beforeDestroy(销毁前)
Destroy(销毁后)

v-model 修饰符

1.lazy 失去焦点或者回车才会 更新model 数据 
2.number 默认返回是string 加上number 修饰返回Number <input type='number' v-model.number='age'>
3.trim 去除字符两边空格 内部调用trime() 方法

Vue 实例生命周期

Vue渲染机制复用

vue 在渲染dom时并不会直接的操作修改dom 而是修改虚拟dom 修改完成后在去渲染 有的dom 不会创建而是修改一些不同的东西直接复用 
	就比如:<input v-if='true' type="text"/><input v-else type="text"/> 切换到另一个时之前输入的值会保留下来
想要解决此问题 可以添加一个key Vue对比Key不同就不会复用了 key='a' key='b'
v-if 和 v-show 区别 false v-if 直接删除dom v-show 修改display 隐藏

中间插入渲染性能优化

image-20210630123448318

当vue 在中间插入值重绘界面时 会产生一个复用 当key 与li值不相符时会直接修改值  复用算法diff a=b;b=c 直接在原来的值上进行修改在 相当于一个位移 可以将key 与li 的值相同 这样就不会 复用 直接 插入 

数组中不能实现响应式的方法

1.通过数组下标修改值 arr[0]=123
解决方法 使用splice arr.splice(0,1,123) 或者 Vue.set(arr,0,'123')

过滤器

一个参数
//html
{{aa | filterAa}}
//js
filters:{
  filterAa(aa){
    // 这额aa就是过滤器传入的参数
  }
}
多个参数
//html
{{aa | filterAa(b,c)}}
//js
filters:{
  filterAa(aa,b,c){
    // 这额aa就是过滤器传入的参数
  }
}

v-model

 vue 的 data数据只是单向绑定 只有model数据改变才会响应 而 view 修改不会影响data
 双向绑定
  一般用于表单 表单和js 数据永远是统一的 view 和model 修改都会触发vue 重绘
  <input v-model="message">
  实现原理 <input :value="message" v-on:input="message=$event.target.value">

组件化思想

将一个复杂得功能分为多个小功能 小功能也可以细分为子功能 最后在组合起来

组件化的基本步骤 
1.创建组件构造器 Vue.extends
2.注册组件 vue.component
3.使用组件 Vue 实例范围内使用组件


1.创建 
	const mycpn=Vue.extend({
        template:`<a> hello vue</a>`
    })
2注册 在html 以什么样的标签名来使用
    Vue.component('my-cpn',mycpn) 
3使用
	<my-cpn></my-cpn>

全局组件和局部组件
  Vue.component('my-cpn',mycpn) //全局注册 
  vue({
      el:"#app",
      components:{
          mysd:mycpn//局部组件 只能在当前实地html 下使用
      }
  })

父组件子组件
	//实例1
	new Vue({
		el:"#app",
		components:{
			'my-cpn':{
					template:`<div>
								<h1>root</h1>
								<my-cpn></my-cpn>
							</div>	`,
					components:{
						"my-cpn":{
                            template:`<div>son</div>`
                           }
					}
			},
		}
	})

抽离

上面的写起来太乱 因该抽离开
1.script
	<script type="text/x-template" id="cpn">
		<h1>你好世界</h1>
	</script>
	new Vue({
		el:'#app',
		components:{
			cpn:{
				template:'#cpn'
			}
		}
	})

2.template
	<template id="cpn">
		<div>
			root
			<cpn></cpn>
		</div>
	</template>
	<template id="cpn1">
			<div>
				<h1>我是root</h1>
			</div>
	</template>
	new Vue({
		el:'#app',
		components:{
			cpn:{
				template:'#cpn',
				components:{
					cpn:{
						template:'#cpn1'
					}
				}
			}
		}
	})

组件数据的存放

组件的data必须是一个函数 返回一个对象
cpn:{
	template:'#cpn1',
     data(){
        return {
            title:'我是标题'
        }
    }
}

为什么组件的data必须是一个函数?
  	组件复用时 每个组件都有自己的逻辑思维所以组件之间不能相互影响
    为了分离开多个组件使用会共共享一个dtat 
function abc(){return {name:'sd'}}
var obj1=abc()
var obj2=abc()
var obj3=abc()
 
这样他们的data才不会相互影响

父子组件之间的通讯

父组件向子组件传递: 在子组件中声明变量名 props['a'] a就是标签属性 props 获取使用当前组件的属性来通信
				<cpn :a=arr></cpn> 获取自定义属性 a的值
				props 也可以使用对象来接收
				props:{
					a:Array,指定以数组的形式来接受 
				}
				
				设置默认值
					props:{
					a:{
						type:Array,
						default(){
						return [1,2,3]
						}
						required:true //此属性表明必须传入 a这个属性来获取
					}
				}
父传子 驼峰标识	接收数据时遇到大写 的标识 在标签使用中使用-代替 cInte ==> <c-inite></c-inite>

子组件向父组件传值 
1.为root定义自定义事件 
	<div id="app">
			<cpn @cpnclick='parentClick'></cpn>	
	</div>
		parentClick(item){
			console.log(item)
		}

image-20210702103659307

父子组件的访问方式

父组件访问子组件 使用$children 或 $refs
	this.$children[0].showname() //$children存储子组件 组件的顺序会影响下标表示的对象
	$refs 只需要在组件身上加上 ref属性就可以拿到		<cpn ref='aaa'></cpn> 
		this.$refs.aaa.data或者方法 推荐使用这个
子组件访问父组件 使用 $parent
		this.$parent.data或者方法
访问根实例 this.$root

ref使用(访问子组件)

<cpn1 ref='son1'></cpn1>
this.$refs.son1.name 访问子组件的name属

ref访问元素

如果ref帮的是 元素那么ref就直接说元素了 thi.$refs.aaa
如果是组件就要用$el来获取元素 this.$refs.aaa.$el

popos使用(访问父组件传过来的值)

父组件传值: <cpn name="aa" sum="bb"></cpn>
子组件访问值: props:['name','sum'],//必须使用props接收才可以访问 this.$props.name 此方式是动态的会根据父组件的修改而修改

调用root 事件 ($emit)

this.$emit(`cpnclick`,item)//事件名,**参数** 这样就可以调用父组件事件了 
注意父组件定义事件 必须是 <cpn @cpnclick="a++"></cpn>

slot

插槽·
基本使用
	<cpn ref='aaa'>
		<a href="">1</a>
		<a href="">2</a>
	</cpn>
	<h1>组件</h1>
	//template
	<slot>
		<h3>预留位置1</h3>//默认不传使用的内容
	</slot>
//最终将cpn 内的所有都替换到 slot中
//替换指定插槽
<cpn ref='aaa'>
	<a href="" slot="center">sd</a>
</cpn>

<slot name="left">左</slot>
<slot name="center">中</slot>
<slot name="right">右</slot>

//执行结果 中被替换了

//插槽传值
<cpn ref='aaa'>
	<template slot="center" slot-scope="slot" >
		{{slot.data}}-{{123}}
	</template>
</cpn>
	<slot name="center" :data="name">{{name}}</slot>
//通过获取 slot 的绑定属性来传递值 再有slot-scope="slot" 来获取所有slot绑定属性

组件通讯实例

	<div id="app">
		我是:{{name}}
			<cpn @stt='aaa' :name='name'></cpn>
	</div>
</body>
<script src="./public/vue.js"></script>
<template id="cpn">
	<div>
		<h2>hello<ccp  @setparent='setparent' :name='name'></ccp></h2>
	</div>
</template>
<script type="text/javascript">
	new Vue({
		el:'#app',
		data:{
			name:'李明'
		},
		methods:{
				aaa(x){
					this.name=x
					console.log('sd',this.name)
				}
		},
		components:{
			'cpn':{
				template:'#cpn',
				props:['name'],
					methods:{
						setparent(x){
							this.$emit('stt',x)
						}
				},
				components:{
					ccp:{
						template:`<h2 @click='setparent'>{{name}}</h2>`,
						props:['name'],
						methods:{
							setparent(x){
								this.$emit('setparent','你好',this.name)
							}
						}
					}
				}
			}
		}
	})

事件总线

有关于解决 组件之间存在复杂的关系 

事件总线

实现方式:

1.main.js
	Vue.prototype.$bus=new Vue() //挂载到原型上让每个组件访问
2.自定义事件 Vue.$bus.$on('abc',fn) //
3.调用事件 this.$bus.$emit('abc',123) 

解决移动端点击300ms延迟

原因:
移动端300ms点击延迟 一般情况下,如果没有经过特殊处理,移动端浏览器在派发点击事件的时候,通常会出现300ms左右的延迟。也就是说,当我们点击页面的时候移动端浏览器并不是立即作出反应,而是会等上一小会儿.

解决方案:
npm i fastclick -D

import FastClick from 'fastclick'
Fastclick.attach(document.body)

懒加载

npm i vue-lazyload -S
Vue.use(VueLazyLoad, {
  preLoad: 1.3,
  error: '//img0.baidu.com/it/u=3839446295,312696076&fm=26&fmt=auto',//加载失败显示的图片
  loading: '//img0.baidu.com/it/u=3180366716,374092945&fm=26&fmt=auto',//加载中显示的图片
  attempt: 1
})

更多参数见官网

vue响应式原理

//1.监听data数据变化 Object.definPrototy()
        Object.defineProperty(obj,'name',{
            set(value){
                console.log('改变了'+value);
             },
            get(){
                return 123//获取始终返回123
            }
        })