1、vue响应式数据变化
建议把vue文档通读一遍
1、vue特点 如果是对象会使用Object.defineProperty,不支持数组的内容变化,或者不支持数组的长度变化
//会把数组重写
2、使用proxy来实现数据的响应式变化
可以支持数组,而且不区分是对象还是数组
proxy缺点,兼容性查,支持就用proxy不支持就用Object.defineProperty
2.vue指令应用
{{}}可以取值,三元运算符,运算
1、vm.$el 指代的是当前的元素,dom更新是异步的(dom操作必备)
2、vm.$nextNick dom加载完之后延迟执行加载
3、vm.$watch()可以观察某个数据发生变化后出发此函数,监控数据变化
4、vm.$data 当前数据对象
5、vm.$options 所以的选项
6、vm.$set
7、vm.$mount挂载 单元测试 在内存中挂载vue实例 ,此时只能$mount属性
vue指令:指令v-有特定功能的,主要操作dom元素
v-for
数据需要循环来操作,{} 数组 string
(2.5+版本必须加key属性,为了做domdiff)
v-for=“(item,key) in arr”
3.vue的指令和过滤器
v-for指令
尽量不要给动态数据 不要用key来渲染 可能会导致浪费性能
v-bind
v-if/ v-else
v-show
:data里面是没有this的
所有的数据都会合并到vm的实例上,但是会被data覆盖掉,不要声明相同的名字(方法名和data里面的属性名不要同名)
v-on绑定事件 可以简写@符号 并且事件参数是$event
<button @click="fn">切换</button>
v-once只渲染一次,渲染后悔产生缓存 下次更新时 会直接从缓存中获取
可以有效的防止组件重新渲染,用的少
v-html
innerHTML会导致xss攻击
<div v-html="element"></div>
data:{
element::'<h1>hello </h1>'
}
2020-1-31 14:12:52
自定义指令
v-model 就是把value值绑定给元素,并且添加input事件
v-bind 只是动态绑定属性
v-model 可以放到任何地方
如何自定义指令?
1、明确指令的作用 就是操作dom,有特定功能
看你希望那个地方用
分全局指令 :不需要每个组件都音乐,只需要全局引用即可
Vue.directive('color',function(el,bingdings,vnode){
el.style.border='1px solid ${bingdings.value}'
})
// 图片懒加载 v-sroll
过滤器和指令都是没有this指向的,,一般过滤器都封装到
Vue.filter(‘toUpper’,function(value,content=1){
return value.sclice(0,count).toUpperCase()+value.slice(count)
})
用法:{{xx | toUpper(3)}}
data:{
xx:‘hello’
}
输出:HELlo
4.vue的动画应用
watch和compucter的区别
计算属性是属性,所以{{getName}}不需要getName()括号
computed 是基于boject.defineProperty gettter / setter
是有缓存的,如果以来的数据不发生变化,不会重新执行方法
watch方法默认掉的是handler方法 // vm.$watch
// 携程对象的目的是为了传递参数
handler(newVal,oldValue){
this.fullName = this.firstName + this.lastName
inmediate:true //首次加载数据,比如子组件props首次获取到父组件传来的默认值时
deep:true //只要属性发生变化,就会触发此函数,默认只监控一次,递归耗性能
}
什么时候用watch,什么时候用computed
只计算一个值的结果用computed,有缓存的
简单的事件,数据变化就发送调用接口用watch ,异步的,视图更新都是异步的
后面更详细的
data ,method,watch,computed
++vue的动画
很少用
animator
触发动画的动作 v-if v-show v-for 路由切换
css添加动画 animation transition
js添加动画 自带的钩子 有一个动画库velocity
v-enter-active
v-leave-active
.v-enter{
opacity:0
}
5.组件的应用
生命周期
组件通信
vue-cli
封装组件
iview elementui-ui
vue-router 原理
vue的应用
响应式数据变化 什么也的数据可以发生变化
vue的指令 14个
自定义指定 自定义过滤器
computed watch moehods 区别
vue动画 在js中如何使用动画,用css如何实现动画
vue组件应用
-vue的树组件
-vue的日历组件
-表单组件
-扩展表格组件
组件的应用
-组件的生命周期 ,每个生命周期做什么内容
-组件的通信 props events parent children ref eventBus vuex
-render方法 element-ui iview
beforCreate:钩子函数,在newVue的时候会最先调用,这个钩子一般没有太多功能,实际在底层中做一些链
//会初始化自己的生命周期,事件方法 $on $emit
created():响应式的数据变化观察 this.$el
无法获取真实dom,这个时候el还没有加载到dom上this.$el是underfine
beforeMount // 这个方法基本用不到,检测有没有template属性
//template渲染成render函数
mounted //挂载后
问:mounted和created真实的区别:
mounted唯一的区别这里面可以获取真实的元素,this.$el
想扩展组件 靠render方法
beforeUpdate //在更新之前再做一次修改,用的很少
updated 更新后,有个缺点,不能在修改值了,容易死循环
数据一变,发请求,怎么办?用watch方法
beforeDestroy 销毁前,一般情况下,清楚定时器,移除绑定的方法,事件
··
destroyed(){}
销毁,属性,数据,不会影响dom
vm.$destroy()//当组件销毁的时候会出发,路由切换的时候,手动销毁
知道顺序和每个生命周期做什么
一般方法卸载mounted方法里面
有个问题,data(){a:'hello'}
mounted(){
this.a='world'
console.log(this.$el.innerHTML)
//问输出什么,是world为什么呢?因为数据加载是异步的 ,怎么解决呢
// 这个时候就需要nextTick()了,等待数据更新完执行这个方法
this.$nextTick(()=>{ //promise.then,setImmediate,MutationObserver,setTimeout
console.log(this.$el.innerHTML)
})
}
父子组件传值
组件的数据来源 data props
inheritattrs:false //不再dom上显示传递的属性,true允许继承
.native 修饰符 相当于给组件的模板最外添加事件
this.$attrs 所有的属性
this.$listeners 所有的方法
<button @click="$listeners.click()">{{msg}}<>
组件数据来源 data props
全局组件 在任何组件中可以直接使用,而且不需要引入,在组件的模板中用
《子传父》
需要点击事件
组件特点 slot插槽
slot默认值 放在slot,默认标签中,而且名字要对上
slot要用template包起来
有3中写法:
父 <template>
123
</template>
zi:
<div> hello
<slot name="default1"> 没对上</slot>
</div>
1 以前的写法 <template slot="default1">
123
</template>
这种方式废弃了,slot="",2.6.0版本以后废弃了
2· <template v-slot:default>123</template>
新的写法,注意v-slot后面是冒号冒号:
3· 简写
<tempalte #default1></template>
还有一种作用域插槽:
!!在html标签中不能给标签大写,属性名必须用-这种方式转驼峰
规范写法:属性名用msg-Abc
props:msgAbc用驼峰写法
<template v-slot:defaylt="{v}">
slot = slot-scope = v-slot
<template>
`` 折叠菜单 collapse
页面中不能放重复属性 :id="_uid"
cldd 任务6组件的应用 56′ 例子
$provide $inject 上下文 ref可以直接获取组件的实例
eventBus vuex
传参的方式: props $emit v-bind
v-on $parent $children
实现组价封装 表单组件 树组件 日历组件
$provide // 在根组件注入数据
$inject //在子组件消费数据
ref讲解
this.$refs.parent.show()
<parent ref="parent"></parent>
$refs 不紧能放在组件上,也可以放在dom上
<div ref="div" v-for="i in 3"></div>
·ref的3种情况,
1 给dom就是一个dom
如果给v-for 出来的就是数组
如果给组件,就是组件的实例
##平级组件的通信
1、通过共同的父亲传参
2、一个全局的发布订阅的方式
eventBus比较适合 简单的数据流
怎么写?
通过一个共同的vue实例,写在原形方法上
Vue.prototype.$bus= new Vue();
// 兄弟组件1
mounted(){
this.$bus.on('吃',(food)=>{
console.log(food)
})
}
// 兄弟组件2
mounted(){
this.$bus.on('吃',"苹果")
}
// 组件的数据流 父组件将数据传递给子组件,子组件不能直接更数据
··重要的语法糖
子组件不能直接更改数据,通过emit
实现一个输入框双向绑定
<div id="app">
<!--this.$on('update:value',pchange) 一样的写法,@update:value 可以改为@u,emit也得改-->
<my-input :value="value" @update:value="pchage">
<!--这种写法就不用写下面的pchange方法了-->
<!--如果改变的属性叫a,对应的方法叫updata.a => :a.sync-->
<my-input :value="value" @update:value="val=>value=val">
<!--简写的改造方法2.5版本后-->
<my-input :value.sync="value"></my-input>
<!--和 @update:value类似-->
<my-input :value="value" @input="val=>value=val">
<!--:value+@input 和 v-model-->
<my-input v-model="value">
//以上都是同步数据用的
</div>
<script>
Vue.compontent('my-input',{
props:['value'],
template:'<input type="text" :value="value" @input="change"/>',
methods:{
change(e){
this.$emit('update:value',e.target.value);
this.$emit('input',e.target.value)
}
}
});
let vm = new Vue({
el:'+app',
data(){
return {value:'hello1111'}
},
methods:{
pchange(val){
this.value = val
}
}
})
</script>
// 注意my-input 的几种写法和语法糖
#v-cli-3.0讲解
第一步:需要安装2个插件 两个命令
npm install @vue/cli @vue/cli-service-global -g
vue serve
怎么配置vue-cli3.0项目
vue create my-app
//vue ui 打开ui界面创建项目,傻瓜式
main.js文件
渲染函数 这个函数比较重要的
默认的main文件中只支持reder方法,不用template
render里面的this是谁?
是个代理Proxy。她代理的目标是当前的实例 new Vue
render:function(h){
return <h1>点我啊</h1>
}
注意(h) 这个h是必要的,不能去掉,不能改掉
组件 1声明2引用3注册
函数组件的上下文
functional:true, //函数式组件,只要render方法不能写template
content就是当前组件的上下文 props slots
例子
列出h1到h5,常规写法写很多标签
简写改进
父组件
<div> <MyTitle :type="1"> hello world</MyTitle></div>
MyTitle.js文件
export default{
functional:true,
reder(h,content){
let t = 'h'+context.props.type;
console.log(context)
return <t>{context.slots().default}</t>
}
}
//这样就实现type=1,就显示h1标题的hello world
日历组件
事件委托
通过dom操作ref方式
cldd如何自己封装日历组件
6.插件的编写
任务10 插件的编写
写一个element-ui插件message的原理和方法 cldd
beforeCreate
7.router
router路由默认有router-link和router-view
this.$router 实际上 就是全局 路由对象 任何页面 都可以 调用 push(), go()等方法
this.$route 用这个属性,表示当前正在用于跳转的路由器对象,可以调用其name、path、query、params等属性;
$route.path当前路由的路径
路由跳转默认会预加载 有个0.js
prefetch 预加载预读取的意思,后台空闲获取更多资源,存储在浏览器缓存中
preload预抓取,浏览器渲染机制之前进行处理的
重定向:
redirect:{path:''}
表单校验:
提供一个对象 :rules="rule"
data
rules:{ //是个数组
username:[
{required:true,triggrt:'nlur'}
]
}
1、提供一个对象 :rules="rule"
2、写data的rules数组
3、需要校验输入框,给输入框加个属性prop="username"
4、required:true,必须填;triggrt:'nlur'什么时候触发,message 消息
#路由钩子
beforeRouteEnter(to,from,next){ //可以做页面的权限,不能拿到this
//参数:去哪,从哪来,是否继续
next(vm=>{
console.log(vm) //这个方法会再组件渲染完毕后调用
})
},
beforeRouterLeave(to,from,next){//离开的是干什么
//场景,提交前,判断form表单是否有值,然后提示
if(this.ruleForm.username && !this.flag){
alert(111)
}else{
next(); //是否继续向下执行
}
}
提交表单之前校验
submit(){
this.$refs.form.validate(valid=>{
if(valid){
this.flag = true;
this.$router.push('user/list')
}
})
}
CLDD 路由练习,首页/个人中心/用户
用户添加,列表
8.vuex
vuex状态管理器 之前是父子通信,eventBus
主要是集中管理状态,组件通信,页面通信
创建容器 store 里面有很多状态
store.dispatch 派发动作,不能直接改状态
Action 处理异步的
mutation 改变状态的唯一途径 通过store.commit()提交
cldd 31秒点击a 加10,b减少10
联系计算器 vuex
2020-3-2 18:16:34
#字体大小
面试题
15.如何让(a==1&&a==2&&a==3)的值为true
//===三个等号不需要类型转换,直接比较
//==尝试类型转换,在进行比较
转换的规则
NaN和任何职都不相等,包括nan
null underfined 如果他们两个自己用==比是相等的,跟其他值不相等
对象跟字符串比较,会把对象转成字符串然后相比
任何一个对象,obj.toString()
其他类型都有转成数字进行比较
字符串转数字,如何转?
toString valueOf 都是对象继承自Object.prototype的方法
toString会返回一个对象的字符在中的描述,valueOf返回对象本身
字符串和数字相比的时候,尝试字符串转成数字
先调用a.valueOf方法判断,如果返回的不是数字,则尝试调用toString方法
然后在用toString的返回值转成数字比较
true转数字时1
http://www.zhufengpeixun.cn/2020/html/94.2.JavaScript.html
16. 说一下arrayBuffer 和 Buffer 的区别 以及应用场景
arrayBuffer 用于前端解析后端返回的 二进制数据,是个二进制字节数组,不能直接操作,
TypeArray类型组件 dataView
arrayBuffer 和blob的区别?
两个字节组成一个数
高位在前和高位 大头在前 小头在后
97的二进制+98的二进制 01100001 01100010
是98+97
parseInt就是把一个字符串转成十进制
0开头8进制
0x开头16进制
数字掉方法
两个点是什么意思? 数字调用方法用的
97..toString(2)
97..toString()==(97).toString()
小括号把数字包起来,相当于把它转为一个对象了,就可以调方法了
blob
如何处理大文件上传
因为只写一个点的话,由于是数字,会被当成 小数点来处理
浮点数可以直接调用原型方法,整数就不可以.
88.88.toString()
88.toString()不行
88..toString()
JavaScript的解释器把数字后的"."偷走了(作为前面数字的小数点)
柯里化 bind原理 深拷贝浅拷贝
进程线程 + 事件环+微任务 +宏任务
大文件上传
9.vuex购物车
1、因UR滴滴组件库cube-ui
2、 商品列表 购物车
3、刷新路径变化
4、获取数据
10.elementui的table展开航数据
<template>
<el-table :data="tableConfig.tableData"
style="width: 100%">
<el-table-column type="expand">
<template slot-scope="props">
<el-form label-position="left"
inline
class="demo-table-expand">
<el-table :data="props.row.infos"
:show-header="false"
style="width: 100%">
<el-table-column v-for="(item, index) in tableConfig.columns"
:key="index"
:label="item.label"
:prop="item.prop">
</el-table-column>
</el-table>
</el-form>
</template>
</el-table-column>
<el-table-column v-for="(item, index) in tableConfig.columns"
:key="index"
:label="item.label"
:prop="item.prop">
</el-table-column>
</el-table>
</template>
<script>
export default {
data () {
return {
resTable: {
tableData: []
},
tableConfig: {
tableData: [],
columns: [
{
prop: 'id',
label: '商品ID',
minWidth: 120,
isResize: true,
labelAlign: 'center',
columnAlign: 'center'
},
{
prop: 'group',
label: '平台',
minWidth: 120,
isResize: true,
labelAlign: 'center',
columnAlign: 'center'
},
{
prop: 'name',
label: '商品名称',
minWidth: 120,
isResize: true,
labelAlign: 'center',
columnAlign: 'center'
},
{
prop: 'price',
label: '价格',
minWidth: 120,
isResize: true,
labelAlign: 'center',
columnAlign: 'center'
},
{
prop: 'desc',
label: '描述',
minWidth: 120,
isResize: true,
labelAlign: 'center',
columnAlign: 'center'
}
]
}
}
},
mounted () {
this.getListData()
},
methods: {
// 获取列表
getListData () {
this.tableConfig.tableData = []
setTimeout(() => {
let res = {
'page': {
'hasPre': false,
'hasNext': false,
'items': [
{
'id': '1298711',
'name': '干果',
'price': '48',
'desc': '价格实惠',
'infos': [
{ 'group': 'taobao', 'name': '开心果', 'price': '48', 'desc': '颗粒大' },
{ 'group': 'jigndong', 'name': '开心果', 'price': '48', 'desc': '颗粒大' },
{ 'group': 'meituan', 'name': '开心果', 'price': '48', 'desc': '颗粒大' }
]
},
{
'id': '1298711',
'name': '干果',
'price': '48',
'desc': '价格实惠开心果',
'infos': [
{ 'id': 11, 'group': 'taobao', 'name': '开心果', 'price': '48', 'desc': '颗粒大' },
{ 'id': 11, 'group': 'jigndong', 'name': '开心果', 'price': '48', 'desc': '颗粒大' },
{ 'id': 11, 'group': 'meituan', 'name': '开心果', 'price': '48', 'desc': '颗粒大' }
]
},
{
'id': '1298711',
'name': '干果',
'price': '48',
'desc': '价格实惠开心果',
'infos': [
{ 'id': 11, 'group': 'taobao', 'name': '开心果', 'price': '48', 'desc': '颗粒大' },
{ 'id': 11, 'group': 'jigndong', 'name': '开心果', 'price': '48', 'desc': '颗粒大' },
{ 'id': 11, 'group': 'meituan', 'name': '开心果', 'price': '48', 'desc': '颗粒大' }
]
}
],
'index': 1,
'size': 15,
'total': 89,
'totalPage': 5
}
}
res = res.page || {}
if (res.items) {
this.total = res.total
this.tableConfig.tableData = (res.items || [])
}
}, 1000)
}
}
}
</script>
<style>
.demo-table-expand {
font-size: 0;
}
.demo-table-expand label {
width: 90px;
color: #99a9bf;
}
.demo-table-expand .el-form-item {
margin-right: 0;
margin-bottom: 0;
width: 50%;
}
</style>
xuexi