vue2.x学习笔记

Vue.config.productionTip=false //阳止 vue在启动时生成生产提示。

BootCDN

MOMENT.JS 日期处理库 dayjs

解构赋值连续写法

{query:{id,title}} 
debugger调试
debugger
debugger 语句用于停止执行 JavaScript,并调用 (如果可用) 调试函数。
使用 debugger 语句类似于在代码中设置断点。
通常,你可以通过按下 F12 开启调试工具, 并在调试菜单中选择 "Console" 。
注意: 如果调试工具不可用,则调试语句将无法工作。
MVC

MVVM
M : 模型(Model) : 对应data中的数据
V : 视图 (View) : 模板
VM : 视图模型(ViewModel) :vue实例对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4vJxQlEj-1651137472216)(C:\Users\mht\AppData\Roaming\Typora\typora-user-images\image-20211212181705266.png)]

回顾 Object.defineproperty方法 reduce
Object.defineproperty('给哪个对象添加属性''添加的属性叫什么名字'{
配置项
value:18,
enumerable:true,//控制属性是否可以枚举,默认false
writable:true,//控制属性是否可以修改,默认false
configurable:true,//控制属性是否可以被删除,默认值是false
//当有人读取obj的age属性时,get函数就会被调用,据返回值就是age的值
    get:function({
		return: number
    }),
//当有人修改了obj的age属性时,set函数(setter)就会被调用,且会收到修改的具体值。
    set(value){
    	console.log('有人修改了age属性,且值是',value)
    	number=value;
    }
})
添加的属性不可以被枚举(遍历)
Object.keys(object)

delete obj.name 

https://www.jianshu.com/p/e375ba1cfc47
reduce()方法可以搞定的东西,for循环,或者forEach方法有时候也可以搞定,那为啥要用reduce()?这个问题,之前我也想过,要说原因还真找不到,唯一能找到的是:通往成功的道路有很多,但是总有一条路是最捷径的,亦或许reduce()逼格更高...
array.reduce(()=>{},0)

callback (执行数组中每个值的函数,包含四个参数)

    1、previousValue (上一次调用回调返回的值,或者是提供的初始值(initialValue))
    2、currentValue (数组中当前被处理的元素)
    3、index (当前元素在数组中的索引)
    4、array (调用 reduce 的数组)

initialValue (作为第一次调用 callback 的第一个参数。)

例子
var arr = [1, 2, 3, 4];
var sum = arr.reduce(function(prev, cur, index, arr) {
    console.log(prev, cur, index);
    return prev + cur;
})
console.log(arr, sum);
打印结果:
0 1 0
1 2 1
3 3 2
6 4 3
[1, 2, 3, 4] 10
这个例子index是从0开始的,第一次的prev的值是我们设置的初始值0,数组长度是4,reduce函数循环4次。

结论:如果没有提供initialValue,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。如果提供initialValue,从索引0开始。
数据代理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qIb2seYZ-1651137472217)(C:\Users\mht\AppData\Roaming\Typora\typora-user-images\image-20211212192220990.png)]

数据代理:通过一个对象代理对另一个对象中属性的操作 读/写
1.Vue中的数据代理:
	通过vm对象来代理data对象中属性的操作(读/写)
2.Vue中数据代理的好处:
	更加方便的操作data中的数据
3.基本原理:
	通过object.defineProperty()把data对象中所有属性添加到vm 上.为每一个添加到vm上的属性,都指定一个getter/setter.
	在getter/setter内部去操作(读/写)data中对应的属性。

let obj1={x:100}
let obj2={y:200}

Object.defineProperty(obj2,'x',{
    get(){
        return obj1.x
    },
    set(value){
        obj1.x=value
    }
})

vue 中的data的数据都是代理的
vm._data===data
vm._data= 里面作了数据劫持

vue原型对象
Vue.prototype
Vue.extend()返回值是VueComponents
图像界面创建
vue ui 图像界面创建

选vue3.x

1.安装插件 
axios
2.安装依赖
echarts 
echarts-gl 3d的库

template 标签包裹dom元素但不生成dom元素
v-model
v-model.number
事件
v-on 简写@  绑定 
@click 点击
@wheel 鼠标滚轮滚动事件
@scroll 滚动条滚动事件

1.onmouseenter和onmouseleave是一组:当鼠标进入指定区域的时候触发,但是不支持冒泡,进入或者离开子组件都不触发
onmouseenter和onmouseleave相当于绑定的区域为A+B
2.onmouseover和onmouseout是一组:当鼠标进入指定区域的时候触发,进入或者离开子组件也都触发

onmouseover和onmouseout相当于绑定的区域为A(不包含B)

事件修饰符
e.preventDefault()阻止默认行为
e.stopPropagation()阻止冒泡
e.target 获取点击的元素
@click.prevent=""阻止默认行为
Vue中的事件修饰符:
1.prevent:止默认事件(常用);
2.stop:阻止事件冒泡(常用);
3.once:事件只触发一次(常用);
4.capture:使用事件的捕获模式; 一般是先捕获在冒泡 冒泡才开始触发事件   加完后就是 捕获的时候就触发事件
5.self:只有event.target是当前操作的元素是才触发事件;
6.passive:事件的默认行为立即执行,无需等待事件回调执行完毕;
键盘事件
keydown按下去
keyup抬起来
keyCOde 键盘编码
@keyup.enter 
常用的按键别名:
回车=>enter
删除=>delete(捕获“删除”和“退格”键)
退出=>esc
空格=>space
换行=>tab(切换焦点必须配置keydown使用)
上=>up
下=>down
左=>left
右=>right
@keyup.caps-lock 切换大小写

2.Vue未提供别名的按健,可以使用按健原始的key值去绑定,但注意要转为kebab-case(短横线命名)
3.系统修饰键(用法特殊):ctrl、alt、 shift、meta
	(1).配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他健,事件才被触发。
	(2).配合keydown使用:正常触发事件。
4.也可以使用keyCode去指定具体的按键(不推荐)
5.Vue.config.keyCodes.自定义健名=键码,可以去定制按键别名
计算属性与监听,过滤
vue所管理的函数都要写普通函数
计算属性
//计算属性
不能开启异步任务的
export default {
		data() {
			return {
				hasWeixinAuth: '您好',
			}
		},
		computed:{
			hash:{
				//get有什么作用?当有人读取hash时,get就会被调用,且返回值就作为hash的值 重复调用走缓存
				//get什么时候调用? 1.初次读取hash的时候调用。2.所有依赖的数据发生变化时
				get(){
					console.log('被调用了');
					return '帅哥'+this.hasWeixinAuth
				},
				//set什么时候调用? 当hash被修改的时候
				set(value){
					console.log('set',value);
					const arr=value.split('-');
					console.log(arr);
				}
			}
		},
		onShow() {
			this.hash='李-四';
		},
		methods: {
			demo(){
				
			}
		}
	}
	
	
	
	简写(只读取不改)
	computed:{
        hsah(){
            console.log('被调用了');
            return '帅哥'+this.hasWeixinAuth
        }
    }

	
监视属性watch
可以做异步任务的
监视属性watch:
1.当被监视的属性变化时,回调函数自动调用,进行相关操作
2.监视的属性必须存在,才能进行监视!!
3.监视的两种写法:
(1).new Vue时传入watch配置
(2).通过vm.$watch监视
watch:{
	isHot:{
       //handler什么时候被调用?当isHot发生改变的时候
        immediate:true,//初始化时让handler调用一下
        deep:true,//深度监听
        handler(newValue,oldValue){
            新值和旧值对比
            console.log('isHot被修改了',newValue,oldValue)
        }
    }
}
vm.$watch('isHot',{
    //handler什么时候被调用?当isHot发生改变的时候
        immediate:true,//初始化时让handler调用一下
        handler(newValue,oldValue){
            新值和旧值对比
            console.log('isHot被修改了',newValue,oldValue)
        }
})

还可以监听计算属性里面的值
export default {
		data() {
			return {
				hasWeixinAuth: '您好',
				isShow:true,
			}
		},
		computed:{
			info(){
				return this.isShow?'炎热':'寒冷'
			}
		},
		watch:{
			info:{
				immediate:true,
				handler(newValue,oldValue){
				    console.log('info被修改了',newValue,oldValue)
				}
			},
		},
		methods: {
			demo(){
				this.isShow=!this.isShow
			}
		}
	}
//深度监听
/**
(1).Vue中的watch默认不监测对象内部值的改变(一层)
(2).N置deep:true可以监测对象内部值改变(多层)
-备注:
(1).Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以!
(2).使用watch时根据数据的具体结构,决定是否采用深度监视-
*/
data() {
	return {
		numbers:{
			a:1,
			b:2
		}
	}
},
watch:{
	'numbers.a':{
		//监视多级结构中某个属性的变化
		immediate:true,
		handler(newValue,oldValue){
		    console.log('a被修改了',newValue,oldValue)
		}
	}numbers:{
		//监视多级结构中所有属性的变化
		deep:true,
		immediate:true,
		handler(value){
		    console.log('a被修改了',value)
		}
	}
},
// 简写(简写了就不能配置了)
info(newValue,oldValue){
	console.log('info被修改了',newValue,oldValue)
}
vm.$watch('isShow',function(newValue,oldValue){
    console.log('info被修改了',newValue,oldValue)
})



    

vue监测数据的原理
vue 怎么检测对象中数据改变的

defineProperty 
加工data 就可以实现对对象进行监视
vue监测数组的原理
数组里面值得变化不是靠set和get来监测的

用这写可以改变原数组的来写 可以相应
包装数组修改数组身上的方法实现的
push push() 方法可向数组的末尾添加一个或多个元素,并返回新的长度。
pop pop() 方法用于删除数组的最后一个元素并返回删除的元素。
shift shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。
unshift unshift() 方法可向数组的开头添加一个或更多元素,并返回新的长度。
splice 
sort 
reverse(颠倒数组中元素的顺序:)

Vue数据监听总结

过滤器
<h3>{{ time | timeFormater('YY年MM月DD日') | mySlice}}</h3>
过滤器本质是个函数
局部过滤器
首先读取time 将time作为参数给timeFormater函数 最好返回值会把他{{ time | timeFormater}}全部替换掉
第一个参数 就是time 阶梯模式往下传 
filters:{
	timeFormater(value,str="YY年MM月DD日 HH:mm:ss"){
		
	}
}


全局的叫filter
Vue.filter('mySlice',function(value){
	return value.slice(0,4)
})

用于插值语法    
绑定值的时候也可以用
有时候电商 1999 => 过滤成1,900
<h3 :x="msg | mySlice ">撒大大</h3>
过滤
filter不改变原数组 返回新数组

应用场景
平时开发中,需要用到过滤器的地方有很多,比如单位转换、数字打点、文本格式化、时间格式化之类的等
比如我们要实现将30000 => 30,000,这时候我们就需要使用过滤器
Vue.filter('过滤器名称'function(){
    
})
//搜索 watch 实现
<body>
    <div id="app">
        <h1>人员列表</h1>
        <button @click.once="add">添加</button>
        <input type="text" placeholder="请输入名字" v-model="keyWord">
        <ul>
            <li v-for="(p,index) in filterPersons" :key="p.id">
                {{p.name}}-{{p.age}}-{{p.sex}}
            </li>
        </ul>
    </div>
    <script>
        new Vue({
            el: '#app',
            data:{
                keyWord:'',
                persons: [
                    { id: '001', name: '马东梅', age: 18,sex:'女' },
                    { id: '002', name: '周冬雨', age: 19,sex:'女' },
                    { id: '003', name: '夏洛', age: 20,sex:'男' },
                    { id: '004', name: '金毛狮王', age: 21,sex:'男' },
                ],
                filterPersons:[]
            },
            filter:{

            },
            watch: {
                keyWord:{
                    immediate:true,
                    handler(newValue){
                        this.filterPersons = this.persons.filter((p)=>{
                            return p.name.indexOf(newValue)!== -1;
                        })
                    }
                }
            },
            methods: {
                
            }
        })
    </script>
</body>

//计算属性的过滤
new Vue({
            el: '#app',
            data:{
                keyWord:'',
                persons: [
                    { id: '001', name: '马冬梅', age: 18,sex:'女' },
                    { id: '002', name: '周冬雨', age: 19,sex:'女' },
                    { id: '003', name: '夏洛', age: 20,sex:'男' },
                    { id: '004', name: '金毛狮王', age: 21,sex:'男' },
                ],
            },
            computed:{
                filterPersons(){
                    return this.persons.filter((p)=>{
                        return p.name.indexOf(this.keyWord)!== -1;
                        console.log(p);
                    })
                }
            }
        })

1.定义:要用的属性不存在,要通过已有的计算属性得来
2.原理:底层借助了objcet.defineproperty方法提供的getter和setter.
3.get函数什么时候执行?
	(1).初次读取时会执行一次。
	(2).当依赖的数据发生改变时会被再次调用。
4.优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。
5.备注:
	1.计算属性最终会出现在vm 上。直接读取使用即可。
	2.如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变
//可以读性高
computed:{
	//方法:函数
}
计算属性与方法的区别
计算属性是基于他们的依赖进行缓存的(依赖指data 中的数据)  比较耗时的计算可以节省性能
方法不存在缓存的  

//监听 处理异步  用于登录
watch:{
	isHot:{
       //handler什么时候被调用?当isHot发生改变的时候
        immediate:true,//初始化时让handler调用一下
        handler(newValue,oldValue){
            新值和旧值对比
            console.log('isHot被修改了',newValue,oldValue)
        }
    }
}
这两个都可以实现相同效果但过程有点不一样
Computed特点:
需要主动调用,具有缓存能力只有数据再次改变才会重新渲染,
否则就会直接拿取缓存中的数据。

Watch特点:
无论在哪只要被绑定数据发生变化Watch就会响应,
这个特点很适合在异步操作时用上。




//过滤器
应用场景
平时开发中,需要用到过滤器的地方有很多,比如单位转换、数字打点、文本格式化、时间格式化之类的等
比如我们要实现将30000 => 30,000,这时候我们就需要使用过滤器
Vue.filter('过滤器名称'function(){
    
})


key作用与原理
用inputd时最好用id 区分
面试题: react. vue中的key有什么作用?(key的内部原理)
1.虚拟DOM中key的作用:
    key是虚拟DOM对象的标识,当状态中的数据发生变化时,Vue会根据【新数据】生成【新的虚拟DON》,随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:
2.对比规则:   
	(1).旧虚拟DOw中找到了与新虚拟DOM相同的key:
		1.若虚拟DOM中内容没变,直按使用之前的真实DOW!
		2.若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM。
	(2).旧虚拟DOM中未找到与新虚拟DOM相同的key
		创建新的真实DOM,随后渲染到到页面。
3.用index作为key可能会引发的问题:
	1.若对数据进行:逆序添加、逆序删除等破环顺序操作:
		会产生没有必要的真实DOM更新==>界面效果没问题,但效率低。
	2.如果结构中还包含输入类的DOM:
		会产生错误DOM更新==>界面有问题。
4.开发中如何选择key?
	1.最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号、学号等唯一值。
	2.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,
		使用index作为key是没有问题的。
收集表单信息
单选框
要配置value值
多选
初始化数据是数组
@submit.prevent  表单提交事件

type="number" v-model.number 输入的字符串转成有效数字

v-model.lazy 失去焦点后在收集数据
v-model.trim 输入首位空格过滤

vue.set()
//改数组里面的值
this.$set('哪个对象''对象的哪个属性','值是什么');
只能给data中某个响应式对象添加属性

//改数组里面的值
this.$set('哪个数组''数组的下标','值是什么');

内置指令
v-text
向其所在的标签插文本
name='牛比'
拿到name的值替换掉整个内容的值
<div v-text=name> </div> => <div>牛比</div>
v-html

v-cloak
主要解决当你网速过慢的时候他不会让你未经过解析的东西跑到页面上去
1.本质是一个特殊属性 Vue实例创建完毕并接管容器后,会删掉v-cloak属性。
2.使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题。
    <style>
        [v-cloak]{
            display: noen;
        }
    </style>
<h1 v-cloak>人员列表</h1>
v-once
1.v-once所在节点在初次动态渲染后,就视为静态内容了。
2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。
<h1 v-once>初始化的n值:{{n}}</h1>
<h1>当前的n值:{{n}}</h1>
<button @click="n++">n++</button>
v-pre
1.跳过其所在节点的编译过程。
2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。
加了之后vue就不去解析他了
自定义指令
directives:{
对象和函数的写法
	big:{
	
	},
	big(){
		
	}
}
生命周期

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eOuR8ee1-1651137472218)(C:\Users\mht\AppData\Roaming\Typora\typora-user-images\image-20211223205619303.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BTd8NRXP-1651137472219)(C:\Users\mht\AppData\Roaming\Typora\typora-user-images\image-20211223205713030.png)]

mounted(挂载完毕)
//Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted

  • 什么是生命周期

    • 一个组件从创建到销毁的过程,就是组件的一生
  • 作用

    • 在不同的阶段做不同的事
  • 分四个阶段

    • a.挂载阶段,只执行一次

      1. beforeCreate

        • 实例初始化后调用,做一些初始化的事件,但组件的data、methods、computed、props、watch…等等选项对象还未创建,数据观察与事件机制尚未形成,也就不能使用data中的状态和methods方法
      2. created

        • 实例已经创建完成之后被调用,可以通过this访问injectpropsdatamethodscomputedwatch等大部分属性和方法了
        • 可以在此发网络请求
      3. beforeMount

        • 挂载前调用,在内存中对模板与数据进行编译结合,但此时还没有挂载到页面上,页面还是旧的,可以在此 对数据进行最后一步修改
      4. mounted

        • 挂载完成,内存中编译好的vnode渲染到了网页上,此时才可以获取dom,但不建议直接操作dom,要用框架的思想通过状态去实现需求
    • b.更新阶段,状态更新了就会触发

      • beforeUpdate
        • 响应式数据更新时调用,当状态发生改变的时候就会触发此钩子函数,页面还没有和最新的数据保持同步,这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器
      • updated
        • 数据与模板相互结合 ,会将新数据挂载到页面上,可以在此获取最新的dom结构,避免在此期间更改状态,因为这可能会导致更新无限循环
    • c.销毁阶段

      • beforeDestroy
        • 在实例销毁之前调用,实例仍然完全可用
        • 一般在这一步做一些重置的操作,比如清除掉组件中的定时器 和 解绑监听的dom事件
      • destroyed
        • 在实例销毁之后调用,所有的事件监听器会被移出,所有的子组件实例也会被销毁,所有的 data 和 methods , 指令, 过滤器 ……都是处于不可用状态。组件销毁后会将vue与当前网页之间的关系进行断开解绑
    • d.错误捕获

      • errorCaptured
        • 当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。
  • keep-alive专属

    • activited
      • 组件被激活时调用
    • deactivated
      • 组件被销毁时调用
组件化编程
非单文件组件
Vue中使用组件的三大步骤:
一、定义组件(创建组件)
二、注册组件
三、使用组件(写组件标签)


一、如何定义一个组件?
	使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options儿乎一样,但也有点区别;
	区别如下:
		1.el不要写,为什么?—最终所有的组件都要经过一个vm的管理,tvm中的el决定服务哪个容器。
		2.data必须写成函数,为什么?——避免组件被复用时,数据存在引用关系。
	备注:使用template可以配置组件结构。
	
二、如何注册组件?	
	1.局部注册:靠new Vue的时候传入components选项
	2.全局注册:菲vue.component('组件名",组件)
	
三、编写组件标签:
	<school></ school>


const schoo = Vue.extend({
	name:'atghg',
	template:``,
	data(){
          return{
          
          }
     },
     methods: {
     
     }
})
//全局注册组件
Vue.components('schoo',schoo)
components:{
	schoo,
}
单文件组件

组件注意事项
1.关于组件名:
	一个单词组成:
        第一种写法(首字母小写):school
        第二种写法(首字母大写):School
	多个单词组成:
		第一种写法(kebab-case命名):my-school
		第二种写法(Camelcase命名):MySchoo1(需要Vue脚手架支持)
	备注:
		(1).组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。
		(2).可以使用name配置项指定组件在开发者工具中呈现的名字。
		
2.关于组件标签:
	第一种写法: <school></ school>
	第二种写法:<school/>
	备注:不用使用脚手架时,<school/>会导致后续组件不能渲染。
	
3.一个简写方式:
	const school = Vue.extend(options)可简写为: const school = options
	底层写了判断他会直接帮你解决
VueComponent构造函数
关于VueComponent:
	1.school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的
	2.我们只需要写<school/>或<school></school>,Vue解析时会帮我们创建school组件的实例对象,
	即Vue帮我们执行的:new VueComponent(options).	
	3.特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!!
	4.关于this指向:
		(1).组件配置中;
			data函数、methods中的函数、watch中的函数、computed中的函数它们的this均是【Vue】
		(2).new Vue()配置中:
			data函数、methods中的函数、watch中的函数、computed中的函数它们的this均是【Vue】
	5.VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。	
    Vue的实例对象,以后简称vm。I
		
	
原型
1.一个重要的内置关系:VueComponent.prototype._proto_ === Vue.prototype
2.为什么要有这个关系:让组件实例对象_(vc)可以访问到Vue原型上的属性、方法。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5U1ZzdHo-1651137472219)(C:\Users\mht\AppData\Roaming\Typora\typora-user-images\image-20220105202936951.png)]

vue脚手架
npm install -g @vue/cli

vue inspecrt > output.js 把vue脚手架默认配置整理成为.js文件

public 里面的index.html 不支持ie8以下版本
		指public目录<%= BASE_URL %>
src
-assets 放静态资源
-components 组件
-main.js 项目入口文件
	Vue.config.productionTip = false 关闭vue生产提示
	new Vue({
  		//将App组件放入容器中
      render: h => h(App),
    }).$mount('#app')

.gitignore ->git忽略文件 不想接受git管理
babel.config.js ->转es5
package.json -> 包管理
	vue-cli-service build webpack打包	
	"lint": "vue-cli-service lint" 语法检查
package-lock.json包管理
README.md 说明笔记


//改默认配置
vue.config.js
vue会将其中的配置跟webpack里面的配置进行合并

render函数
关于不同版本的Vue:、
	1.vue.js 与vue.runtime.xxx.js的区别:
        (1).vue.js是完整版的Vue,包含:核心功能+模板解析器。
        (2). vue.runtihe.xxx.js是运行版的Vue,只包含:核心功能;没有模板解析器。
	2.因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用render函数接收到的createElement函数去指定具体内容。

ref属性
1.被用来给元素或子组件注册引用信息(id的替代者)
2.应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)
3.使用方式:
	打标识: <h1 ref="xxx">.....</h1>或<School ref="xxx"></School>
	获取:this.$refs.xxx


<h1 ref="title">人员列表</h1>

console.log(this.$refs.title); 拿到真实DOM元素

也可以拿到组件的实例对象 可以用于组件间通信 

props配置
 父组件也可以给子组件传方法
 第一种
 props:['schoolName'],简单接收
 
 第二种
 // 接收收同时对数据进行类型限制
    props:{
        school:String,
        number:Number
    }
 第三种
 // 接收收同时对数据 进行类型限制 +默认值的指定+必要性的限制
    props:{
        school:{
            type:String,//school类型是字符串
            required:true,//school是必要的传
        },
        number:{
            type:Number,
            required:false,
            default:99,//默认值
            default()=>{
				return 
        	}
        }
    }
 
 
 要是想改传过来的值可以在data中重新定义一个 myNumber:this.number
 props 优先级更高 先准备props中的数据在准备data中的数据
 
 备注: props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,
 若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据
mixin混入
export default {
    name:'School',
    data() {
        return {
            name:'大哥大'
        };
    },
    mixins:[mixin]
}
上面这个组合中的每一个配置项在混合中都可以写

以你的数据为主
生命周期除外 都执行 混入中的生命周期执行在前


全局混入  main.js
import {hunhe,hunhe2} from "./mixin"

Vue.mixin(hunhe)
Vue.mixin(hunhe2)

插件plugins.js
plugins.js

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GaGM4OG6-1651137472219)(C:\Users\mht\AppData\Roaming\Typora\typora-user-images\image-20211228205448219.png)]

本地存储webStorage
浏览器通过 Window.sessionStorage 和Window.localStorage 属性来实现本地存储机制
取不到返回null
//浏览器关了也不会消失
保存数据
localStorage.setItem('msg','18')
对象用jsoN存
 localStorage.setItem('person',JSON.stringify(obj))
 
 读取数据
  console.log(localStorage.getItem('msg'))
  
  删除数据
  localStorage.removeItem('msg')
 
 清空本地数据
 localStorage.clear();
 
 
//session 浏览器中的 会话浏览器关闭就没了
保存数据
sessionStorage.setItem('msg','18')
对象用jsoN存
sessionStorage.setItem('person',JSON.stringify(obj))
 
读取数据
console.log(sessionStorage.getItem('msg'))
  
删除数据
sessionStorage.removeItem('msg')
 
清空本地数据
sessionStorage.clear();

自定义事件
给组件用的
子给父传递东西
this.$emit
 this.$emit('student','您在噶那么');
 vue使用$emit时,父组件无法触发监听事件的原因是:
$emit传入的事件名称只能使用小写,不能使用大写的驼峰规则命名
 
 
 
<HelloWorld ref="student" />
this.$refs.student.$on('students',this.students)
this.$refs.student.$once('students',this.students)
自定义事件解绑
this.$off('school');//解绑一个自定义事件
this.$off(['school','demo']);//解绑多个自定义事件
this.$off();//解绑所有的自定义事件


销毁
vm vc
销毁后所有自定义事件的全都不奏效了
this.$destroy();
destroyed(){

}
事件总线(GlobalEventBus)
用事件总线好点

const Demo = Vue.extend({});
const d = new Demo()
Vue.prototype.x=d

哥哥组件
绑定事件总线
this.x.$on('hello',(data)=>{
   console.log('我是School组件,收到了数据',data);
})
弟弟组件
sndtStudent(){
   this.x.$emit('hello',666)
}


//标准写法
new Vue({
  render: h => h(App),
  beforeCreate(){
    Vue.prototype.$bus=this //安装全局事件总线  $bus就是当前应用的vm
  }
}).$mount('#app')

建一个config文件

用完给解绑了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cl1Gg8I7-1651137472220)(C:\Users\mht\AppData\Roaming\Typora\typora-user-images\image-20220105210314770.png)]

消息订阅与发布
组件通信

消息订阅与发布
1.订阅消息:消息
2.发布消息: 消息内容

订阅什么名字 发布什么名字
推荐 pubsub-js
pub(publish发布)sub(subscribe订阅)

School组件
mounted() {
    // this.$bus.$on("hello", (data) => {
    //   console.log("我是School组件,收到了数据", data);
    // });
    // 订阅消息   函数中有两个参数  一个是消息名 一个数据   
    pubsub.subscribe('hello',(msgName,darta)=>{
        console.log("有个人发布了hello消息,hell消息的回调执行了",msgName,darta);
    })
  },
  
   beforeDestroy(){
    //   this.$bus.$off('hello')
    // 取消订阅
    pubsub.unsubscribe(this.pubId);
  }
  
  
  student组件
  sndtStudent(){
            // this.$bus.$emit('hello',this.name)
            // 发布消息
            pubsub.publish('hello',666)
}
  
 第二中方式
 mounted() {
    // 订阅消息   函数中有两个参数  一个是消息名 一个数据    每个订阅的id都不一样
    this.pubId=pubsub.subscribe('hello',this.demo)
  },
  methods: {
    demo(msgName,darta){
         console.log("有个人发布了hello消息,hell消息的回调执行了",msgName,darta);
    }
  },
  beforeDestroy(){
    //this.$bus.$off('hello')
    // 取消订阅
    pubsub.unsubscribe(this.pubId);
  }
  
  
  student组件
  sndtStudent(){
            // this.$bus.$emit('hello',this.name)
            // 发布消息
            pubsub.publish('hello',666)
}
 
 

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-srK0l7Xr-1651137472220)(C:\Users\mht\AppData\Roaming\Typora\typora-user-images\image-20220105213823487.png)]

$nextTick下一轮
1.语法: this.$nextTick(回调函数)
2.作用:在下一次DOM更新结束后执行其指定的回调。
3.什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。

上面一个input框隐藏了
this.$nextTick(function(){
	this.refs.inputTitle.focus()
})
过度动画

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NnXY4X3n-1651137472221)(C:\Users\mht\AppData\Roaming\Typora\typora-user-images\image-20220108160226474.png)]

进入的起点
.动画名-enter
进入的终点
.动画名-enter-to
插槽
默认插槽
<slot></slot>
默认插槽
<template>
  <div class="father">
    <list title="美食" >
      <img src="@/assets/logo.png" alt="">
    </list>
    <list title="游戏">
      <ul>
        <li v-for="(item,index) in games" :key="index">{{item}}</li>
      </ul>
    </list>
    <list title="电影">
      <video src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" width="100%" controls palyauto="palyauto"></video>
    </list>
  </div>
</template>


<template>
    <div class="list_box">
        <h1>{{title}}分类</h1>
        <!--定义一个插槽(挖个坑,等着组件的使用者进行填充)-->
        <slot>我是一些默认值,当使用者没有传递具体结构时,我会出现</slot>
    </div>
</template>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fbHMNvJZ-1651137472221)(C:\Users\mht\AppData\Roaming\Typora\typora-user-images\image-20220108171024696.png)]

具名插槽
<template>
  <div class="father">
    <list title="美食" >
      <img slot="center" src="@/assets/logo.png" alt="" style="display:block;margin:0 auto;">
      <a slot="footer" href="">更多美食</a>
    </list>
    <list title="游戏">
      <ul slot="center">
        <li v-for="(item,index) in games" :key="index">{{item}}</li>
      </ul>
      <div slot="footer">
        <a  href="">单机游戏</a> 
        <a  href="">网络游戏</a>
      </div>
    </list>
    <list title="电影">
      <video slot="center" src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" width="100%" controls palyauto="palyauto"></video>
      <template slot="footer" >
        <div >
          <a  href="">经典</a> 
          <a  href="">热门</a>
        </div>
        <div>
          欢迎来看
        </div>
      </template>
      <!-- 使用template 可以用新的写法 -->
      <!-- <template v-slot:footer >
        <div >
          <a  href="">经典</a> 
          <a  href="">热门</a>
        </div>
        <div>
          欢迎来看
        </div>
      </template> -->
    </list>
  </div>
</template>





<template>
    <div class="list_box">
        <h1>{{title}}分类</h1>
        <!--定义一个插槽(挖个坑,等着组件的使用者进行填充)-->
        <slot></slot>
        <slot name="center">我是一些默认值,当使用者没有传递具体结构时,我会出现</slot>
        <slot name="footer">我是一些默认值,当使用者没有传递具体结构时,我会出现</slot>
    </div>
</template>



[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ci0fWBw5-1651137472221)(C:\Users\mht\AppData\Roaming\Typora\typora-user-images\image-20220108172904792.png)]

作用域插槽
<template>
  <div class="father">
    <list title="游戏">
      <!-- 作用域插槽必须要用template包一层 -->
      <template scope="gamesData">
        <ul>
          <li v-for="(item, index) in gamesData.games" :key="index">{{ item }}</li>
        </ul>
      </template>
    </list>
    <list title="游戏">
     <template slot-scope="gamesData">
       <!-- 第二种新写法slot-scope="gamesData" -->
       <h4>{{gamesData}}</h4>
        <!-- { "games": [ "红色警戒", "穿越火线", "劲舞团", "超级玛丽" ], "msg": "hello" } -->
        <ol>
          <li v-for="(item, index) in gamesData.games" :key="index" style="color:red">{{ item }}</li>
        </ol>
      </template>
    </list>
  </div>
</template>




<template>
    <div class="list_box">
        <h1>{{title}}分类</h1>
        <!--定义一个插槽(挖个坑,等着组件的使用者进行填充)-->
        <slot :games="games" msg="hello">我是一些默认值,当使用者没有传递具体结构时,我会出现</slot>
    </div>
</template>
export default {
    name: 'List',
    props:["listData","title"],
    data() {
        return {
            games:[ "红色警戒","穿越火线","劲舞团","超级玛丽"],
        };
    },

    mounted() {
        
    },

    methods: {
        
    },
};

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0EpYxuYc-1651137472222)(C:\Users\mht\AppData\Roaming\Typora\typora-user-images\image-20220108193727515.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lLyFyBS8-1651137472222)(C:\Users\mht\AppData\Roaming\Typora\typora-user-images\image-20220108193742816.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UnPZaIli-1651137472222)(C:\Users\mht\AppData\Roaming\Typora\typora-user-images\image-20220108193748435.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NbaPmpf4-1651137472223)(C:\Users\mht\AppData\Roaming\Typora\typora-user-images\image-20220108193754156.png)]

路由
vue-router
https://www.jianshu.com/p/b3f4c1b3aab2
home首页的路由 search   login
public 里面引用默认样式



router.currentRoute //获取当前页面的router

路由组件与非路由组件的区别?
1:路由组件一般放置在pages|views文件夹,非路由组件一般放置components文件夹中
2:路由组件一般需要在router文件夹中进行注册(使用的即为组件的名字),非路由组件在使用的时候,一般都是以标签的形式使用
3:注册完路由,不管路由路由组件、还是非路由组件身上都有$route、$router属性
$route:一般获取路由信息【路径、query. params等等】
$router:一般进行编程式导航进行路由跳转【push|replace1】 两者区别是能不能记住历史记录

5.路由跳转
路由的跳转有两种形式:
声明式导航router-link,可以进行路由的跳转
编程式导航push|replace,可以进行路由跳转

编程式导航:声明式导航能做的,编程式导航都能在,
但是编程式导航除了可以进行路由跳转,还可以做一些其他的业务逻辑。

路由传参,参数有几种写法?
params参数:属于路径当中的一部分,需要注意,在配置路由的时候,需要占位
query参数:不属于路径当中的一部分,类似于ajax中的queryString /home?k=v&kv= 不需要占位

//路由传递参数:
//第一种:字符串形式
// this. $router. push(" /search/" + this.keyword+" ?k="+this. keyword.toUpperCase());
//第二种:模板字符串
// this.$router.push( /search/${this.keyword} ?k=${this. keyword.toUpperCase()})
//第三种:对象
//this.$router.push({name: "search" , params: {fkeywond:this.keyword } , query:[ k:this.keywordg))

// 字符串
router.push('home')
// 对象
this.$router.push({path: '/login?url=' + this.$route.path});
// 带查询参数,变成/backend/order?selected=2
this.$router.push({path: '/backend/order', query: {selected: "2"}});
// 命名的路由
router.push({ name: 'user', params: { userId: 123 }})


嵌套路由

router-view

<router-view/> 是用来承载当前级别下的子级路由的一个视图标签,此标签的作用就是显示当前路由级别下一级的页面。
路由传参
params传参必须用 name

query 可以name 也可以 path

$route: Object 

$router: VueRouter
this.$router.back()返回上一页
this.$router.go()
this.$router.push('/') 返回到别的页面自己决定

编程导航传参
params与query一样的
this.$router.push('/login?token=mhtsm')  传参 可以传字符串也可以传对象
      this.$router.push({
        name:'Login',
        query:{
          token:'nam',
          age:15,
        }
      });
this.$route//拿参数
//结构赋值拿参
 const {query:{name},token,path}=this.$route;
    console.log(this.$route);
    console.log(token,name,path);
    // console.log(this.$route.query.age);
params与query 一样


组件传参 可以传字符串也可以传对象
<router-link to="/about/5570">跳转</router-link>
<router-link to="{name:'/login',query:{token:'mht'}}">跳转</router-link>
 created() {
    const {params:{cid},name,path}=this.$route;
    // console.log(this.$route);
    console.log(cid,name,path);
    // console.log(this.$route.query.age);
  },
   {
    path: '/about/:cid',
    name: 'About',	
   }

嵌套路由 重定向

关于 vue-router 里 router-link 被激活时的状态

exact 是一个单独的属性,正确用法是 <router-link to="/home" active-class="bianlan" exact>。
这样,只有当路径刚好是 /home 时才会添加 bianlan 类名,而当路径是 /home/something 时则不会(因为不 exact)。


//二级路由
借助 vue-router,使用嵌套路由配置,就可以很简单地表达这种关系。
{
    path: '/home',
    name: 'Home',
    component: Home,
    // 重定向 // 默认显示组件
    redirect:'/home/aw',
    // 嵌套子路由
    children:[
      {
        path:'/home/aw',
        name:'Aw',
        component:Aw
      },
      {
        path:'/home/ak',
        name:'Ak',
        component: Ak,
      }
    ]
  },

组件(要有视图容器)
  <nav>
      <router-link to="/home/aw">大儿子</router-link>
      <router-link to="/home/ak">小儿子</router-link>
    </nav>
    <router-view></router-view>
//哪个被选中根据类名给样式


//三级嵌套路由
路由的props配置
{
    path: '/home',
    name: 'Home',
    component: Home,
    // 重定向 // 默认显示组件
    redirect:'/home/aw',
    // 嵌套子路由
    children:[
      {
        path:'/home/aw',
        name:'Aw',
        component:Aw
      },
      {
        path:'/home/ak',
        name:'Ak',
        component: Ak,
        //props的第一种写法,值为对象,该对象中的所有key-value都会以props的形式传给Detail组件。
        // props:{a:1,b:'hello'}
        
        //props的第二种写法,值为布尔值,若布尔值为真,就会把该路由组件收到的所有params参数,以props的形式传给Detail组件
        // props:true
          
        //props的第三种写法,值为函数
        props({query:{id,title}){
        	return {id,title}       
        }
      }
    ]
  },

router-link的replace属性
<router-link replace ></router-link> 点击后的路由没有历史记录

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GjENSKC3-1651137472223)(C:\Users\mht\AppData\Roaming\Typora\typora-user-images\image-20220111210937303.png)]

编程式路由导航

this.$router.push{
	path:'/'
	query:{
		id:1
	}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B93P1YzZ-1651137472224)(C:\Users\mht\AppData\Roaming\Typora\typora-user-images\image-20220111211606614.png)]

缓存路由组件
路由切换 input里面得到数据即将被销毁了

包含的组件才会缓存 include="写组件名"
<keep-alive include="News">   
<router-view></router-view>
</keep-alive>

多个缓存用数组
<keep-alive include="["News","Index"]">   
<router-view></router-view>
</keep-alive>
新的生命周期钩子路由组件独有的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SsR9hUWV-1651137472224)(C:\Users\mht\AppData\Roaming\Typora\typora-user-images\image-20220111213118598.png)]


缓存的无法清除定时器
News组件
activated(){
	News组件出现在我们面前激活调用一次
},
deactivated(){
	News组件消失在我们面前激活调用一次
}

$nextTick(()=>{
	修改完DOM后放到页面了 才调用这个生命周期钩子
})
vue导航守卫

你可以使用 router.beforeEach 注册一个全局前置守卫:

const router = new VueRouter({ ... })
                              
router.beforeEach((to, from, next) => {
  // ...
})

当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中

每个守卫方法接收三个参数:

  • to: Route: 即将要进入的目标 路由对象
  • from: Route: 当前导航正要离开的路由
  • next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。
    • next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
    • next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
    • next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: truename: 'home' 之类的选项以及任何用在 router-linkto proprouter.push 中的选项。
    • next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。
// 全局前置守卫 任何路由都会触发钩子
router.beforeEach((to,from,next)=>{
  // console.log(webCookie.getCookie('token'));
  const token=webCookie.getCookie('token');
  if(token){
    console.log();
  }else {
    // 未登录
    if(to.name==='login'){
      return next()
    }else {
      return next({
        path:'/login'
      })
    }
  }
  next();
})
//路由独享守卫
 {
    path: '/zhidingyizhiling',
    name: 'ZhidingiZhiling',
    component: ZhidingiZhiling,
    //路由独享守卫
    beforeEnter(to,from,next){
      const isLogin=true
      if(!isLogin){
        next()
      }else{
        next('/')
      }
    }




//元信息 全局后置守卫
router.afterEach((to,from)=>{
  document.title=to.meta.title
})

{
    path: '/home',
    name: 'Home',
    component: Home,
    exact:true,
    // 重定向 // 默认显示组件
    redirect:'/home/aw',
    // 嵌套子路由
    children:[
      {
        path:'/home/aw',
        name:'Aw',
        component:Aw,
        meta: { title: '网易aw' }//相当于网页的标题
      },
      {
        path:'/home/ak',
        name:'Ak',
        component: Ak,
        meta: { title: '网易ak' }
      },
      {
        path:'/home/three',
        name:'three',
        component:three,
        redirect:'/home/three/sanjia',
        children:[
          {
            path:'/home/three/sanjia',
            name:'Sanjia',
            component:Sanjia
          },
          {
            path:'/home/three/sanjib',
            name:'Sanjib',
            component: Sanjib
          },
        ]
      }
    ]
  },
      
//组件内的守卫
  beforeRouteEnter(to, from, next) {
    // 在渲染该组件的对应路由被 confirm 前调用
    // 不!能!获取组件实例 `this`
    // 因为当守卫执行前,组件实例还没被创建
    //beforeRouteEnter 守卫 不能 访问 this,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。
    //不过,你可以通过传一个回调给 next来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。
    next(vm=>{
        vm.isShow=true;
         // 通过 `vm` 访问组件实例
   	 })
  },
      注意 beforeRouteEnter 是支持给 next 传递回调的唯一守卫。对于 beforeRouteUpdate 和 beforeRouteLeave 来说,this 已经	可用了,所以不支持传递回调,因为没有必要了。
      
  beforeRouteUpdate(to, from, next) {
    // 在当前路由改变,但是该组件被复用时调用
    // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
    // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 可以访问组件实例 `this`
     console.log(this.$route.params.cid);
      next()
  },
  beforeRouteLeave(to, from, next) {
    // 导航离开该组件的对应路由时调用
    // 可以访问组件实例 `this`
    //这个离开守卫通常用来禁止用户在还未保存修改前突然离开。该导航可以通过 next(false) 来取消。
    const comfirms=window.confirm('你确定要离开吗🐱');//返回布尔值
    if(comfirms){
      next(true);//跳转
    }else{
      next(false);//不跳转
    }
  },
  
js-cookie && webapi-cookie
webCookie.getCookie('token');//获取cookie
滚动行为()

使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样。 vue-router 能做到,而且更好,它让你可以自定义路由切换时页面如何滚动。

注意: 这个功能只在支持 history.pushState 的浏览器中可用。

当创建一个 Router 实例,你可以提供一个 scrollBehavior 方法: 写在index.js 中

const router = new VueRouter({
  // mode: 'history',
  base: process.env.BASE_URL,
  routes,
  scrollBehavior(to,from,savedPosition){
    
  }
})

路由缓存keep-alive
<keep-alive>
富文本编辑器
UEditor
CKEditor 4 
Vue-html5-editor
wangeditor
quill
TinyMec  、、 https://www.cnblogs.com/lucky-cat233/p/13426508.html  https://madewith.cn/315
mavon-editor
....
TinyMec最好用,不但符合系统风格,整体简洁美观,而且插件比较丰富,
在 Vue 项目中引入 tinymce 富文本编辑器
项目中原本使用的富文本编辑器是 wangEditor,这是一个很轻量、简洁编辑器
但是公司的业务升级,想要一个功能更全面的编辑器,我找了好久,目前常见的编辑器有这些:
UEditor:百度前端的开源项目,功能强大,基于 jQuery,但已经没有再维护,而且限定了后端代码,修改起来比较费劲
bootstrap-wysiwyg:微型,易用,小而美,只是 Bootstrap + jQuery...
kindEditor:功能强大,代码简洁,需要配置后台,而且好久没见更新了
wangEditor:轻量、简洁、易用,但是升级到 3.x 之后,不便于定制化开发。不过作者很勤奋,广义上和我是一家人,打个call
quill:本身功能不多,不过可以自行扩展,api 也很好懂,如果能看懂英文的话...
summernote:没深入研究,UI挺漂亮,也是一款小而美的编辑器,可是我需要大的
在有这么参考的情况下,我最终还是选择了 tinymce 这个不搭梯子连官网都打不开的编辑器(简直是自讨苦吃),主要因为两点:
1. GitHub 上星星很多,功能也齐全;
2. 唯一一个从 word 粘贴过来还能保持绝大部分格式的编辑器;
3. 不需要找后端人员扫码改接口,前后端分离;
4. 说好的两点呢!
注意:这篇博客仅适用于 Tinymce 4.x

//tinymce   vue使用tinymce中提示Object(...) is not a function
版本太高了,vue2中不能使用@tinymce/tinymce-vue为4以上版本;
所以卸载以前的:npm uninstall @tinymce/tinymce-vue
安装低版本的:例如:npm install @tinymce/tinymce-vue@3.0.1 -S
而tinymce版本大小无所谓

关于tinymce富文本编辑器获取文本内容和设置文本内容
1、一个编辑器: 
获取内容:tinymce.activeEditor.getContent() 
设置内容:tinymce.activeEditor.setContent(“需要设置的编辑器内容”)

2、多个编辑器(下面的“[0]”表示第一个编辑器,以此类推): 
获取内容:tinymce.editors[0].getContent() 
设置内容:tinymce.editors[0].setContent(“需要设置的编辑器内容”)

3、获取不带HTML标记的纯文本内容: 
var activeEditor = tinymce.activeEditor; 
var editBody = activeEditor.getBody(); 
activeEditor.selection.select(editBody); 
var text = activeEditor.selection.getContent( { ‘format’ : ‘text’ } );

取到的 text 即为纯文本内容。
$emit && ref

https://blog.csdn.net/qq_16339527/article/details/53231725

arguments
最后我们还可以看到arguments还有一个叫做callee的属性,这个属性是表示的是当前函数的一个引用,简单点说,这个属性里面存储的我们调用的这个函数的代码,实在无法理解的时候,又到了console.log大显身手的时候了。

function showcallee() {
    var a = '这里是代码';
    var b = '这是另一段代码';
    var c = a + b;
    console.log(arguments.callee);
    
    return c;

showcallee();
看到结果的你是不是和我一样惊呆了呢,这不就是我写的代码吗,arguments.callee完完整整的把这个函数的这段代码返回了。
$emit 
/**
	直接传对象报错 我写的自组件this.$emit里面, 是一个对象, 其实传的是它的地址
	所以, 后面这样改写子组件就ok了
	let obj=JSON.parse(JSON.stringify({time:this.Time,isShow:false}))
 	this.$emit('handClickTime',obj)
*/
ref
可以获取dom节点也可以调用子组件的方法
this.$nextTick()的使用
vue项目中的excel文件的导入 导出

https://blog.csdn.net/weixin_43844392/article/details/88747237

1、添加依赖
使用npm安装:
 npm install -S file-saver xlsx(这里其实安装了2个依赖)
 npm install -D script-loader

yarn
yarn add file-saver
yarn add xlsx
yarn add script-loader --dev

<template>
  <div>
    <div>
      <div>
        <el-button style="float: right;" type="primary" @click="exportExcel">导入excel表</el-button>
      </div>
      <div>
        <el-button style="float: right;" type="primary" @click="exportExcel">导出excel表</el-button>
      </div>
    </div>
<!--    <el-table :data="studnetData" style="width: 100%;" ref="multipleTable"  v-loading="fullscreenLoading" id="exportXlsx"></el-table>-->
    <el-table
        :data="studnetData"
        stripe
        ref="multipleTable"  v-loading="fullscreenLoading" id="exportXlsx"
        style="width: 100%">
      <el-table-column
          prop="date"
          label="日期"
          width="180">
      </el-table-column>
      <el-table-column
          prop="name"
          label="姓名"
          width="180">
      </el-table-column>
      <el-table-column
          prop="address"
          label="地址">
      </el-table-column>
    </el-table>
  </div>
</template>

<script>
import XLSX from 'xlsx';
import FileSaver from 'file-saver';
export default {
  name: "Excel",
  data() {
    return {
      studnetData: [{
        date: '2016-05-02',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1518 弄'
      }, {
        date: '2016-05-04',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1517 弄'
      }, {
        date: '2016-05-01',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1519 弄'
      }, {
        date: '2016-05-03',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1516 弄'
      }]
    }
  },
  methods:{
    exportExcel() {
      //根据给的id获取table表,选取元素的时候加上,{raw:true}可以使表格正常导出,消除科学计数法
      let wb = XLSX.utils.table_to_book(document.getElementById('exportXlsx'), {
        raw: true
      })
      let wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: true, type: 'array' })
      try {
        //给xlsx文件赋值名字
        FileSaver.saveAs(new Blob([wbout], { type: 'application/octet-stream' }), 'test.xlsx')
      } catch (e) { if (typeof console !== 'undefined') console.log(e, wbout) }
      return wbout
    },
  }
}
</script>

<style scoped>

</style>
cookie

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6zENaRqB-1651137472225)(C:\Users\mht\AppData\Roaming\Typora\typora-user-images\image-20211217093316086.png)]

面试
谁给的访问的时候就用谁

//闭包
	使用完变量会自动释放
	使用函数内部的变量在函数执行完后,仍然存活在内存中(延长了局部变量的里命周期)
	让函数外部可以操作(读写)到函数内部的数据(变量/函数)
//promise是用来解决两个问题的:
避免回调地狱
可以支持多个并发的请求
可以解决异步的问题

//深拷贝浅拷贝
赋值
浅拷贝 
	先创建一个新的对象
	通过循环拷贝里面的值
深拷贝 
浅拷贝碰到引用数据类型 就是拷贝的内存地址 
let neMemo = JS0N.parse(JS0N.stringify(this.list));


//veu响应式  数据响应式主要 数据劫持和数据代理
数据劫持 
defineProperty 给我一个数据把这个数据给篡改了里面添加get set
数据代理
每次对数据行如何操作的的时候就知道如何写了



VUEX
可以直接跳过Actions 用Mutations

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mo7UiIsd-1651137472225)(C:\Users\mht\AppData\Roaming\Typora\typora-user-images\image-20220108205101903.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PWvjtyqF-1651137472225)(C:\Users\mht\AppData\Roaming\Typora\typora-user-images\image-20220109131520554.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MtJRb8HM-1651137472226)(C:\Users\mht\AppData\Roaming\Typora\typora-user-images\image-20220109131926689.png)]

两种方法
第一种
Vuex
-store.js
第二种
store
-index.js


集中式状态管理的一个VUE插件 对vue应用中多个组件的共享状态进行集中式管理(读/写),也是组件间通信的方式,且合适用于任意组件间通信


什么时候使用
1.多个组件依赖于同一状态
⒉.来自不同组件的行为需要变更同—状态
多个组件共享一个状态
数据中心 统一处理
用辅助函数调用

1.npm i vuex
2.Vue.use(Vuex)
3.store
4.vc==>store


state:{
	状态:就是数据data
}
getters:{
	VUEX中的计算属性
}
mutations:{
	更新状态
}
actions:{
	异步处理
	调用后端接口的时候用的
}


import Vuex from "vuex";

//准备actions—用于响应组件中的动作
// const actions = {}

//准备mutations—用于操作数器(state)
// const mutations  = {}

// 准备getter-用于将state中的数据进行加工
//const getters  = {}

//准备state—用于存储数据
// const state = {}

export default new Vuex.Store({
  state: {

  },
  getters:{

  },
  mutations: {

  },
  actions: {

  },
  modules: {

  },
});
四个map方法的使用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KtvN1LLi-1651137472226)(C:\Users\mht\AppData\Roaming\Typora\typora-user-images\image-20220109155921867.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BuHADlG6-1651137472226)(C:\Users\mht\AppData\Roaming\Typora\typora-user-images\image-20220109161840083.png)]

<script>
import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'
export default {
  name: "Vuex",

  data() {
    return {
        n:1,//用户选择的数字
        // sum:0,//当前的和
    };
  },
  computed:{
    //借助mapState生成计算属性,从state中读取数据。(对象写法)
    // ...mapState({he : 'sum ' ,xuexiao: 'school ' ,xueke : ' subject'}),
    //借助mapState生成计算属性,从state中读取数据。(数组写法)
    ...mapState(['sum','school','subject']),

    //借助mapGetters生成计算属性,从state中读取数据。(数组写法)
    // ...mapGetters({bigSum: 'bigSum'})
    //借助mapGetters生成计算属性,从state中读取数据。(数组写法)
    ...mapGetters(['bigSum'])
  },
  mounted() {
      console.log('vuex',this.$store);
      console.log();
  }, 
  methods: {
    //   ...mapMutations({法方名:'commit的名字',})
    //借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法)
    ...mapMutations({increment:'JIA'}),

    //借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(数组写法)
    // ...mapMutations(['JIA'),

    //   会被解析成下面
    //   increment(event){
    //      this.$store.commit('JIA',value);
    //   }
    //   increment(){
    //       this.$store.commit('JIA',this.n);
    //   },
      decrement(){
        this.sum -= this.n;
      },
      incrementOdd(){
          if(this.num%2 !==0){
            this.sum += this.n;
          }
      },
      incrementWait(){
          setTimeout(()=>{
              this.sum += this.n;
          },500)
      }
  },
};
</script>
子给父传东西
1.用props 传个函数
<!--通过父组件给子组件传递函数类型的props实现:子给父传递数据-->
<School :getSchoolName="getSchoolName""/>

2.父组件给子绑定一个自定义函数  用  this.$emit('student','子给父传递东西');
<!--通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第一种写法,使用@或v-on)--><l-- <Student @atguigu="getstudentName" /> -->

3.ref
<!--通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第二种写法,使用ref)-->
<Student ref="student"/>

    this.$refs.student.$on('students',this.students)
    this.$refs.student.$once('students',this.students)


父组件调用子组件方法
子组件上定义ref="refName",  父组件的方法中用 this.$refs.refName.method 去调用子组件方法
lodash
//引入方式:是把lodash 全部功能函数引入
import _ from 'lodash';

**1:安装**
cnpm install lodash -S
**2:main.js中导入**
import  _ from 'lodash'
**3:绑定到Vue全局变量中使用**
Vue.prototype._ = _ 
4:在页面中使用
this._.now()

mockjs
使用步骤
1).在项目当中src文件夹中创建mock文件夹
2).第二步准备json数据(mock文件夹中创建相应的JSON文件)
3).把mock数据 需要的图片放置到public文件夹中[public文件夹在打包的时候,会把相应的资源原封不动的打包到dist文件夹中]
4).在mock文件下创建 mockServe.js 。通过mockjs模拟数据   
5).mockServe.js 文件在入口文件中引入(至少需要执行一次,才可以模拟数据)
UI
npm install ant-design-vue

import Antd from "ant-design-vue";
import "ant-design-vue/dist/antd.css";
Vue.use(Antd)
vue3

‘school’,‘subject’]),

//借助mapGetters生成计算属性,从state中读取数据。(数组写法)
// ...mapGetters({bigSum: 'bigSum'})
//借助mapGetters生成计算属性,从state中读取数据。(数组写法)
...mapGetters(['bigSum'])

},
mounted() {
console.log(‘vuex’,this.$store);
console.log();
},
methods: {
// …mapMutations({法方名:‘commit的名字’,})
//借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法)
…mapMutations({increment:‘JIA’}),

//借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(数组写法)
// ...mapMutations(['JIA'),

//   会被解析成下面
//   increment(event){
//      this.$store.commit('JIA',value);
//   }
//   increment(){
//       this.$store.commit('JIA',this.n);
//   },
  decrement(){
    this.sum -= this.n;
  },
  incrementOdd(){
      if(this.num%2 !==0){
        this.sum += this.n;
      }
  },
  incrementWait(){
      setTimeout(()=>{
          this.sum += this.n;
      },500)
  }

},
};




#### 子给父传东西

1.用props 传个函数

<School :getSchoolName=“getSchoolName”"/>

2.父组件给子绑定一个自定义函数 用 this.$emit(‘student’,‘子给父传递东西’);

3.ref

this.$refs.student.$on('students',this.students)
this.$refs.student.$once('students',this.students)

#### 父组件调用子组件方法

子组件上定义ref=“refName”, 父组件的方法中用 this.$refs.refName.method 去调用子组件方法


#### lodash

//引入方式:是把lodash 全部功能函数引入
import _ from ‘lodash’;

1:安装
cnpm install lodash -S
2:main.js中导入
import _ from ‘lodash’
3:绑定到Vue全局变量中使用
Vue.prototype._ = _
4:在页面中使用
this._.now()


#### mockjs

使用步骤
1).在项目当中src文件夹中创建mock文件夹
2).第二步准备json数据(mock文件夹中创建相应的JSON文件)
3).把mock数据 需要的图片放置到public文件夹中[public文件夹在打包的时候,会把相应的资源原封不动的打包到dist文件夹中]
4).在mock文件下创建 mockServe.js 。通过mockjs模拟数据
5).mockServe.js 文件在入口文件中引入(至少需要执行一次,才可以模拟数据)




#### UI

npm install ant-design-vue

import Antd from “ant-design-vue”;
import “ant-design-vue/dist/antd.css”;
Vue.use(Antd)


#### vue3

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值