Vue知识点
文章目录
1. vue介绍
核心理念
- 数据驱动视图:数据发生变化时,用户界面也会发生变化,无需手动修改DOM
mvvm三要素
- modal:数据
- viewModal:vue实例
- view:视图
工作过程简述
- 数据和视图之间通过vue实例进行通讯,modal发生变化时,vm能够监听到这种变化,并通知给view视图做出页面渲染,页面有事件触发时,vm也能监听到事件,通知modal进行数据响应变化
2. 计算属性
应用场景
- 解决模板{{}}中放入过多逻辑会让模板难以维护
好处
- 不是方法,而是存在缓存,当依赖项发生变化才会重新计算
3. 侦听器
- 监听数据变化时应该做个某些操作
- 配合防抖,节流
4. 生命周期
- Vue实例从创建到销毁的过程
挂载阶段
- beforeCreate:Vue实例初始化之后,事件初始化,组件父子关系确定
- created:初始化prop,data,computed,watch,methods已经完成
- beforeMount:渲染template模板,虚拟dom
- mounted:$el挂载,template模板替换
更新阶段
- beforeUpdate:获取更新前的各种状态数据
- updated:所有的状态数据都是最新的
配合keep-alive组件
- activited:组件激活
- deactivited:组件失活
销毁阶段
- beforeDestroy:组件销毁前执行,用于清除一些定时器
- destoryed
- this.$destroy()方法,销毁资源
5. 组件
原则
- 可复用
- 可维护
- 单一功能
6. 在单页面中创建和使用组件
全局注册组件
- 创建
注意data节点为一个函数
Vue.component('componentA',{
template:"<div>一个A组件</div>",
data(){
return {
msg:'hello'
}
},
method:{
showMsg(){
console.log('msg')
}
}
})
普通页面的vue实例的data节点为一个对象
<script>
let vm=new Vue({
el:'#app',
data:{
msg:'message'
}
})
</script>
- 使用(vue实例中使用使用短横线)
<component-a></component-a>
- 在其他组件中使用(使用驼峰命名法)
Vue.component('componentB',{
template:"<div>新组件:<componentA></componentA> </div>"
})
局部注册组件
const mySon={
template:'<p>子组件</p>',
data(){
return {
}
}
}
// 其他组件中局部注册mySon组件(驼峰命名法)
Vue.component('father',{
template:'<div> 子组件<mySon></mySon> </div>',
components:{
mySon:mySon
}
})
// vue实例中注册(短横线法)
const vm=new Vue({
el:'#app',
data:{
},
components:{
"my-son":mySon
}
})
// 使用
<my-son></my-son>
7. 组件通讯
父向子通讯
- props选项
Vue.component('father',{
// 注意短横线传值
template:'<div><son :F-text="context"></son> </div>',
data(){
return {
context:'父组件的数据'
}
},
// 局部注册子组件
components:{
son:{
props:['Ftext'],
template:'<p>来自父组件的值{{Ftext}}</p>'
}
}
})
子向父通讯
- 自定义事件
Vue.component('father',{
// 注意短横线传值
// 监听子组件触发的事件
template:'<div><son :F-text="context" @msgToFather="sonMsgHandler"></son> </div>',
data(){
return {
context:'父组件的数据'
}
},
methods:{
sonMsgHandler(val){
console.log(val)
}
}
// 局部注册子组件
components:{
son:{
props:['Ftext'],
template:'<p>来自父组件的值{{Ftext}}</p>
// 触发子组件向父组件传输数据的按钮
<button @click="msgToFather">向父组件发生数据</button>
',
methods:{
msgToFather(){
this.$emit('msgToFather','666')
}
}
}
}
})
兄弟组件通信
- 通过事件总线
// 事件总线,空的vue实例,监听事件触发变化
const eventBus=new Vue()
// 兄弟组件1
Vue.component('componentA',{
// 注意短横线传值
// 监听子组件触发的事件
template:'<div>兄弟组件1
<button @click="sendMsg"></button>
</div>',
data(){
return {
context:'父组件的数据'
}
},
methods:{
sonMsgHandler(val){
console.log(val)
},
// 兄弟发送方,发送数据,通过总线发送
sendMsg(){
eventBus.$emit('sendMsg',context)
}
}
})
// 兄弟组件2
Vue.component('componentB',{
// 注意短横线传值
// 监听子组件触发的事件
template:'<div>兄弟组件1</div>',
data(){
return {
context:'父组件的数据'
}
},
methods:{
sonMsgHandler(val){
console.log(val)
},
// 接收兄弟组件发送的数据,eventBus接收
receiveMsg:{
eventBus.$on('sendMsg',data=>{
console.log('兄弟的信息'+data)
})
}
}
})
8. 插槽
- 暴露预留位置给父组件,让父组件确定预留位置的模板
默认插槽
// 插槽定义
const son={
template:"
<div>
Error
// 默认插槽
<slot>默认内容</slot>
</div>
"
}
Vue.component("alert-box",{
template:"
<div>子组件插槽内容
<son>1234<son>
</div>
"
})
具名插槽
// 插槽定义
const son={
template:"
<div>
Error
// 默认插槽
<slot>默认内容</slot>
// 具名插槽,带上名字
<slot name="main"></slot>
<slot name="footer"></slot>
</div>
"
}
Vue.component("alert-box",{
template:"
<div>子组件插槽内容
<son>
<template slot="main">main内容</template>
<template slot="footer">footer内容</template>
// 默认内容
1234
<son>
</div>
"
})
作用域插槽
- 子组件的数据可以通过插槽传送给父组件,让父组件确定每一项的特殊显示
// 需求:定义的一个userList组件,渲染父组件传递过来的数组
// 1. 在不更改userList组件逻辑的情况下,实现列表中特定项加粗
Vue.component("userList",{
template:"
<ul>
<li :key="item.id" v-for="item in userList">
// 使用作用域插槽,将每一项数据传输给父组件,使用者确定是否加粗
<slot :info="item">
{{item.name}}
</slot>
</li>
</ul>
",
props:['userList']
})
// vue 实例使用
const vm=new Vue({
el:'#app',
data:{
userList:[{
id:1,
name:'zs'
},{
id:2,
name:'zs'
},{
id:3,
name:'zs'
}]
},
components:{
"user-list":userList
}
}
})
// 标签使用
<user-list :userList="userList">
// 我们通过作用域插槽使第二项加粗
<template slot-scope="scope">
<strong v-if="scope.info.id===2"></strong>
</template>
<user-list>
作用域插槽再一个案例
每次只能生成相同结构的列表,一旦业务需要发生了变化,组件就不再使用了。比如,我现在有了新的需求,在一个列表的每个列表项前面加上一个小的logo
,我总不能又写一个新的组件来适应需求的变化吧?
这里就可以使用作用域插槽来解决这个问题。
具体的实现代码如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>作用域插槽案例</title>
</head>
<body>
<div id="app">
<!-- 如果没有传递模板,那么子组件的插槽中只会展示用户名 -->
<my-list title="用户列表" :content="listData"></my-list>
<!-- 传递模板 -->
<my-list title="用户列表2" :content="listData">
<template slot-scope="scope">
<img src="./one.png" width="20"/>
<span>{{scope.item.userName}}</span>
</template>
</my-list>
</div>
<script src="./vue.js"></script>
<script>
Vue.component("my-list", {
props: ["title", "content"],
template: `
<div class="list">
<div class="list-title">
{{title}}
</div>
<div class="list-content">
<ul class="list-content">
<li v-for="item in content" :key="item.id">
<!--这里将content中的每一项数据绑定到slot的itemb变量上,在父组件中就可以获取到item变量-->
<slot :item="item">{{item.userName}}</slot>
</li>
</ul>
</div>
</div>
`,
});
const vm = new Vue({
el: "#app",
data: {
listData: [
{ id: 1, userName: "张三" },
{
id: 2,
userName: "李四",
},
{
id: 3,
userName: "王五",
},
],
},
});
</script>
</body>
</html>
在上面的代码中,我们首先在子组件my-list
中,添加了作用域的插槽。
<ul class="list-content">
<li v-for="item in content" :key="item.id">
<!--这里将content中的每一项数据绑定到slot的itemb变量上,在父组件中就可以获取到item变量-->
<slot :item="item">{{item.userName}}</slot>
</li>
</ul>
同时在父组件中,使用对应的插槽
<div id="app">
<!-- 如果没有传递模板,那么子组件的插槽中只会展示用户名 -->
<my-list title="用户列表" :content="listData"></my-list>
<!-- 传递模板 -->
<my-list title="用户列表2" :content="listData">
<template slot-scope="scope">
<img src="./one.png" width="20"/>
<span>{{scope.item.userName}}</span>
</template>
</my-list>
</div>
再回到开始的问题,作用域插槽到底是干嘛用的?很显然,它的作用就如官网所说的一样:将组件的数据暴露出去。而这么做,给了组件的使用者根据数据定制模板的机会,组件不再是写死成一种特定的结构。
以上就是作用域插槽的应用,需要你仔细体会。
8.1 vue组件化的理解
- 定义:可复用的Vue实例,VueComponent组件实例
- 增加代码的复用性
- 什么时候使用:
- 通用组件
- 业务组件
- 页面组件
- 如何使用
- Vue.component, component节点
- 通信:
props,$emit,$on
- 内容分发:插槽,template
- 本质:组件配置–>VueComponent–>render–>vDom—Dom
9. vue常用Api
vue.set
- 用于设置响应式数据,使视图能够更新
`Vue.set(target,propertyName,value)`
// 设置不是响应式数据的情况,视图不会更新渲染
//批量更新身高,动态的给users中添加身高属性
batchUpdate() {
this.users.forEach((c) => {
c.height = 0;
});
},
// 动态添加,属性变成响应式,视图会进行渲染
// 视图不会渲染,怎么办呢
batchUpdate() {
this.users.forEach((c) => {
// c.height = this.height;
Vue.set(c, "height", this.height);
});
},
vue.delete
- 用于删除响应式属性时,视图更够更新
`Vue.delete`
vm.$on()
vm.$emit()
- 用于事件总线事件的事件传递
// 挂载在Vue的原型对象的,Vue.prototype.$bus=new Vue()
// 实现一个message组件
9.2 vm.$once,vm.$off
vm.$once
- 监听某个事件触发,触发一次后移除监听
vm.$once('test事件名',function(res){
})
vm.$off
- 移除自定义的事件监听器
vm.$off() // 移除所有的事件监听器
vm.$off('test') // 移除该事件所有的监听器
vm.$off('test', callback) // 只移除这个回调的监听器
10. 过滤器
基本使用
- 全局注册
Vue.filter('filterName',function(val){
// 对原来的值进行处理,返回新的值
return val
})
- 使用
<div>{{msg|filterName}}</div>
局部注册
new Vue({
data:{
},
filters:{
filterName:function(val){
return newVal
}
}
})
带参数的过滤器
Vue.filter("filterName",function(val,arg1,arg2){
return val+arg1+arg2
})
// 使用
<div>
{{date|format('yyyy-MM-dd','arg2')}}
</div>
11 自定义指令
基本使用
// 定义
Vue.directive("focus",{
// 固定写法
inserted:function(el){
el.focus()
}
})
// 使用
<input type="tetx" v-focus/>
带参数的自定义指令
// 定义
Vue.directive("color",{
// 固定写法
inserted:function(el,payload){
// 注意想要获取value
el.style.color=payload.value.color
}
})
// 使用
<div type="tetx" v-color="{color:'blue'}"/>
局部使用
directives:{
color:{
// 固定写法
// bind函数只会执行一次
bind:function(el,payload){
el.style.color=payload.value.color
}
}
}
12. 渲染函数
- 完全使用JavaScript渲染模板
render函数的基本结构
render:function(createElement){
return createElement(
// 三个参数 {string|object,Array}
tag, // 标签名称
data, // 标签属性的数据对象
children // 子节点数组
)
}
组件中使用render函数
// 渲染h1-h6的标题
Vue.component("heading",{
props:{
lever:{
}
},
render(h){
return h(level){
'h'+level,
{attrs:{title:this.title}},
this.$slot.default // 子节点vNode
}
}
})
// 使用
<heading :level="1">{{title}}</heading>
13. mixins(混入)
let myMinxins={
created:function(){
},
methods:{
testMethod(){
}
}
}
Vue.component("minxin名称",{
mixins:[myMixin]
})
// 局部混入
minxins:{
'mixins名称':[myMixin]
}
22、插件
前面我们讲解的混入,组件封装等都可以提高组件的复用功能。
但是这种方式不适合分发,也就是不适合将这些内容上传到github
上,npm
上。而这种情况最适合通过插件
来实现。
插件通常用来为Vue
添加全局功能。插件的功能范围一般有下面几种:
- 添加全局方法或者属性。例如:‘element’
- 添加全局资源
- 通过全局混入来添加一些组件选项。例如
vue-router
- 添加
vue实例
方法,通过把它们添加到Vue.prototype
上实现 - 一个库,提供自己的
API
,同时提供上面提到的一个或多个功能,例如vue-router
插件声明
Vue.js
的插件应该暴露一个 install
方法。这个方法的第一个参数是 Vue
构造器,第二个参数是一个可选的选项对象:
MyPlugin.install = function (Vue, options) {
// 1. 添加全局方法或 property
Vue.myGlobalMethod = function () {
// 逻辑...
}
// 2. 添加全局资源
Vue.directive('my-directive', {
bind (el, binding, vnode, oldVnode) {
// 逻辑...
}
...
})
// 3. 注入组件选项
Vue.mixin({
created: function () {
// 逻辑...
}
...
})
// 4. 添加实例方法
Vue.prototype.$myMethod = function (methodOptions) {
// 逻辑...
}
}
https://www.cnblogs.com/luozhihao/p/7414419.html