vue学习

408 阅读6分钟

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
}

QQ图片20200209190838

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"
4required: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
#字体大小

面试题

image-20200301205131745

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 0110001098+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