# code-210322 **Repository Path**: zxfjd3g/code-210322 ## Basic Information - **Project Name**: code-210322 - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 6 - **Forks**: 0 - **Created**: 2021-07-05 - **Last Updated**: 2021-12-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # day01 ## 1. 变量相关问题 ``` - 变量到底是什么? - 可以变化的量, 由变量名和变量值组成, 名称是标识, 值是可以变化的 - 一个变量对应一块小内存, 变量名是这块内存的标识名称, 用于查找这块内存, 变量的值就是内存中保存的数据 - 基本类型变量与引用类型变量的区别是什么? - 根据变量内存中保存的数据来区分 - 基本类型变量: 内存中保存的基本类型的数据 - 引用类型变量: 内存中保存的是地址值 - 给变量赋值到底做了什么? - 将基本类型数据赋给变量: 将数据保存在变量内存中 - 将对象赋给变量: 将对象在内存中的地址值保存在变量内存中 - 将另一个变量赋给变量: 将右侧变量内存中的数据(基本数据/地址值数据)拷贝保存到左侧变量内存 - 函数传参, 到底是值传递还是引用传递? - 函数调用时, 是将实参变量的数据拷贝一份赋值给形参变量 - 只是实参变量数据可能是基本类型, 也可能是引用类型的(地址值) - 有哪些改变变量值的方式? - 只能通过赋值改变 - c.m = 2: 改的是c变量指向的对象内部的属性数据, c本身没有变化的(对象内存的位置没变) - 如何理解下面2句重要的话(编码演示说明)? - 2个引用变量指向同一个对象, 如果通过一个变量修改对象内部的数据 => 另一个变量也能看到原对象(新数据) - 2个引用变量指向同一个对象, 让其中一个变量指向一个新的对象 => 另一个引用变量看到的是老的对象 ``` ## 2. 函数与对象相关重要问题 ``` 1. 如何理解/证明函数也对象? - 证明: instanceof 为 true - 函数有对象的所有特性: 属性与方法 - 可以调用/执行 - 有特有的属性: prototype - 有特有的方法: call()/apply()/bind() 2. 区别实例对象与函数对象? - 实例对象: new构造函数产生对象 ==> 简称 对象 - 函数对象: 将函数作为对象使用时称为函数对象 3. 区别方法与属性? - 方法是一种特别的属性, 特别之处是属性值是函数 - 什么属性才称为方法: 当属性值为函数时我们称之为方法 4. 区别方法与函数? - 定义在对象中的或通过对象调用的 ==> 方法 - 不是在对象中定义 / 不通过对象调用 ==> 函数 5. 判断是回调函数的3个条件? - 我们定义的 - 我们没有直接调用 - 在某个时刻或条件下会执行 6. 回调函数需要确定的3个问题? - 什么时候调用? - 用来做什么的? - this是谁? 7. 区别函数的定义和函数的执行 执行函数定义: 创建函数对象/原型对象/函数名变量 执行函数: 执行函数体中的语句 执行函数定义是执行函数的前提 ``` ## 3. 表达式a.b的内部解析流程 ``` 1. 查找a变量 沿着作用域链查找, 如果没有找到, 报错: ReferenceError,否则得到变量的值 准备找b属性, 但手里必须要有对象, 得到看a的值 如果是null/undefined ==> TypeError 如果是number/string/boolean ==> 创建对应包装类型对象 引用地址值 ==> 找到对应的对象 2. 查找b属性 先在对象自身上查找, 如果找到了返回它, 如果没有找到, 沿着原型链查找 没有: 返回 undefined 有: 返回它 ``` ## 4. 原型链内存分析 ```js function Fn () {} const fn1 = new Fn() const fn2 = new Fn() const o1 = new Object() const o2 = {} console.log(Fn instanceOf Object) console.log(Fn instanceof Function) console.log(Object instanceof Function) console.log(Object instanceof Object) console.log(Function instanceof Object) console.log(Function instanceof Function) console.log(fn1 instanceof Function) console.log(Object instanceof Fn) ``` ![原型与原型链结构图](README.assets/原型与原型链结构图.png) ## 5. Git的基本使用 1. 创建本地仓库 1. 配置忽略 2. git init 3. git add . 4. git commit -m "xxxx" 2. 创建远程仓库 1. 指定名称 2. 指定是公开的 3. 将本他仓库的代码推送到远程仓库 1. 关联: git remote add origin gitee上的url 2. 推送: git push origin master 4. 如果本地代码有变化 1. git add . 2. git commit -m "xxxx" 3. git push origin master 5. 如果远程有变化 1. git pull origin master 6. 新来的 1. git clone url ## 6. ES6常用新语法 ``` 1. let / const / 块作用域 2. 解构赋值: 解构对象或数组 3. 数值扩展: bigint 4. 字符串扩展: 模板字符串 / includes 5. 函数扩展: 箭头函数 / 形参默认值 / rest(剩余)参数 6. 对象扩展: 属性和方法简写, 扩展对象 7. 数组扩展: 扩展数组 / find() / findIndex() / Array.from() 9. 新容器: Map和Set 10. 类语法: class / static / constructor / super / extends 11. 新的异步语法: Promise / aysnc与await 12. 模块化: export / default / import ``` ## 7. Promise的基本使用 ``` Promise是异步编程的新方案 可以通过其.then的链式调用来解决回调地狱问题 Promise(执行器函数) Promise的三个状态 pending fulfilled rejected 状态只能改变一次 要么是pending ==> fulfilled, 要么是pending ==> rejected then返回的promise的结果状态如何判断? 简洁表达: 由then指定回调函数的执行结果 详细表达: 4种情况 情况1: 抛出错误 ==> 失败, reason为抛出的错误 情况2: 返回一个失败的promise ==> 失败, reason为就失败的promise的reason 情况3: 返回一个成功的promise ==> 成功, vlaue为就成功的promise的value 情况4: 返回非promise对象值 Promise.all(promises): 只有所有的都成功了才成功, 成功的value为所有成功promise的value组成的数组 只要有一个失败的, 直接失败, reason为失败promise的reason ``` ## 8. axios的基本使用 - 测试接口: - [https://api.github.com/search/users?q=a](https://api.github.com/search/users?q=${value})a - http://39.98.123.211:8170/admin/acl/index/login ``` 请求携带参数的形式? (3种) 1. query参数: url问号的参数 2. params参数: 与路由中的带冒号的路径对应的 3. body参数: 请求体参数(post请求) http://localhost:8080/user/1?name=tom&age=12 http://localhost:8080/user/3?name=jack&age=13 axios使用XMLHttpRequest和Promise封装的ajax请求库 有一系列发请求的语法: axios(url) axios({ url: '', // 路径中可以拼params参数数据, 也可以拼query参数 method: 'POST/GET/PUT/DELETE', params: {}, // query参数 data: {}, // 请求体参数 }) axios.get(url, {params: {name: 'tom', age: 12}}) axios.post(url, data) // 添加请求拦截器: 发送请求前执行 axios.interceptors.request.use((config) => { console.log('请求拦截器执行...', config) config.headers.token = 'xxxxa123213' return config }) // 添加响应拦截器 axios.interceptors.response.use( response => { console.log('响应拦截器的成功的回调', response.data) // return response return response.data // return undefined }, error => { console.log('响应拦截器失败的回调') // throw error return Promise.reject(error) } ) ``` # day02 ## 双向数据绑定与MVVM - 双向数据绑定 ==> 通过v-model来展现双向数据绑定 - 模板显示能根据data中的数据动态显示 ==> 数据绑定 - 当改变页面输入, 数据会自动更新data中 - MVVM模式 - M: Model 模型, 在vue就是包含可变数据的data对象 - V: View 视图, 在vue就是动态的模板页面 - VM: ViewModel 视图模型, 在vue就是Vue的实例 ## 模板 - html + js 动态/模板页面 - 插值: {{expression}} 向标签体中动态插入数据显示 - 指令(directive): vue自定义的以v-开头的一些标签属性 - v-model: 双向数据绑定 - v-bind: 指定动态的属性值 - v-on: 绑定事件监听 ## 计算属性与监视 - Object.defineProperty(): 给对象定义属性 - 可以动态计算属性值: getter - 可以监视属性值的变化: setter - 计算属性 - 当要显示的值是由已有数据动态计算确定 - getter: fullName () {return 动态值} - getter/setter: fullName: {get () {}, set() {}} - 有缓存, 多次读取, 只计算一次, 效率高 - 监视 - 当某个数据变化时, 我们就需要做一些什么操作 ==> 就得用监视 - 基本写法 ``` watch: { // 只有数据发生改变时才调用 firstName (value) {}, firstName: { handler (value) {}, immediate: true // 在初始时就会调用第一次 } } ``` - 监视的回调中可以进行异步操作, 但计算属性getter中是不可以 ## class与style绑定 - :class="类名字符串": 类名不确定 - :class="{类名1: true/false, 类名2: true/false}": 确定类名, 但不确定有没有 - :style="{样式名: 值, 样式名2: 值}" ## 条件渲染 - v-if / v-else与v-show: 标签结构的显示与隐藏效果 - 实现的本质不同 - v-if直接删除标签来隐藏, 重新显示时需要再创建 - v-show通过样式来隐藏, 重新显示时不需要重新创建, 只需要修改样式 - v-show: 以空间换时间: 占用的空间更大, 但速度会快 - 如果有有频繁的切换, 用v-show相对好些 ## 列表渲染 - 使用 v-for 遍历数组 ```
  • {{item.name}}
  • ``` - vue内部如何监视数据变化从而更新页面(数据绑定) - 对象中的属性 - 通过defineProerty给属性添加getter/setter来实现对属性数据的监视的 - 问题: - 添加新属性, 界面不会显示 - 直接删除已有属性, 界面不会更新 - 数组中的元素 - 对数组中用于更新元素的一系列方法进行重写 - 调用数组原生的对应方法去更新元素 - 更新界面 - push/pop/shift/unshift/splice/sort/reverse - 有限制: 只能通过重写的几个数组方法来更新元素, 如果直接通过下标更新元素界面不会更新 - 直接更新length属性, 界面不会变化 # day03 ## 事件处理 ``` 1. 绑定监听: v-on:xxx="fun" @xxx="fun" @xxx="fun(参数)" 默认事件形参: event 隐含属性对象: $event 2. 事件修饰符: .prevent: 阻止事件的默认行为 event.preventDefault() .stop: 停止事件冒泡 event.stopPropagation() .once: 事件只响应一次 3. 按键修饰符 .keycode: 操作的是某个keycode值的健 .enter: 操作的是enter键 ``` ## 表单数据收集 ``` 1. 使用v-model自动收集表单项输入数据 2. @submit.prevent 来监听表单提交并阻止表单自动提交 ``` ## vm/组件对象的生命周期 ``` 1. vue对象的生命周期 1). 初始化显示 * beforeCreate(): 不能通过this访问data中的数据和methods中的方法 * created(): 可以通过this访问data中的数据和methods中的方法 * beforeMount(): 不能通过ref得到标签对象 * mounted(): 可以通过ref得到标签对象 2). 更新状态: this.xxx = value * beforeUpdate(): 通过ref得到是老的界面标签 * updated(): 通过ref得到的是新的界面标签 3). 销毁vue实例: vm.$destory() * beforeDestory() * destoryed() 2. 常用的生命周期方法 created()/mounted(): 发送ajax请求, 启动定时器等异步任务 beforeDestory(): 做收尾工作, 如: 清除定时器 ``` ## 过渡&动画 ``` 1. vue动画的理解 操作css的trasition或animation vue会给目标元素添加/移除特定的class 2. 基本过渡动画的编码 1). 在目标元素外包裹 2). 定义class样式 1>. 指定过渡样式: transition 2>. 指定隐藏时的样式: opacity/其它 3. 过渡的类名 xxx-enter-active: 指定显示的transition xxx-leave-active: 指定隐藏的transition xxx-enter: 指定隐藏时的样式 xxx-leave-to: 指定隐藏时的样式 ``` ## 自定义过滤器 ``` 1. 理解过滤器 功能: 对要显示的数据进行特定格式化后再显示 注意: 并没有改变原本的数据, 可是产生新的对应的数据 2. 编码 1). 定义过滤器 Vue.filter(filterName, function(value[,arg1,arg2,...]){ // 进行一定的数据处理 return newValue }) 2). 使用过滤器
    {{myData | filterName}}
    {{myData | filterName(arg)}}
    3. 日期处理工具库 moment dayjs: 更小 moment/daysj(time).format(格式字符串) ``` ## 指令 ``` 1. 内置指令 v-text : 更新元素的 textContent v-html : 更新元素的 innerHTML v-if : 如果为true, 当前标签才会输出到页面 v-else: 如果为false, 当前标签才会输出到页面 v-show : 通过控制display样式来控制显示/隐藏 v-for : 遍历数组/对象 v-on : 绑定事件监听, 一般简写为@ v-bind : 强制绑定解析表达式, 可以省略v-bind v-model : 双向数据绑定 2. 自定义指令 1. 注册全局指令 Vue.directive('my-directive', function(el, binding){ el.innerHTML = binding.value.toupperCase() }) 2. 注册局部指令 directives : { 'my-directive': function(el, binding) { el.innerHTML = binding.value.toupperCase() } } 3. 使用指令 v-my-directive='xxx' ``` ## 插件的定义的使用 ``` 1. 自定义vue插件 1) 如果插件是对象, 对象必须要有一个install 2) 如果插件是函数, 将这个函数当作install方法对待 2. 使用插件 引入插件包 声明使用插件: Vue.use(插件) ``` ## 列表key问题 ``` 面试题: 1). react/vue中的key的作用/内部原理 2). 为什么列表的key尽量不要用index 1. 虚拟DOM的key的作用? 1). 简单的说: key是虚拟DOM对象的标识, 在更新显示时key起着极其重要的作用 2). 详细的说: 当列表数组中的数据发生变化生成新的虚拟DOM后, React进行新旧虚拟DOM的diff比较 a. 能找到对应的key item数据没变, 直接使用原来的真实DOM item数据变了, 对原来的真实DOM进行数据更新 b. 没有对应的key 根据item数据创建新的真实DOM显示 2. key为index的问题 1). 添加/删除/排序 => 产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低 2). 如果item界面还有输入框 => 产生错误的真实DOM更新 ==> 界面有问题 注意: 如果不存在添加/删除/排序操作, 用index没有问题 3. 解决: 使用item数据的标识数据作为key, 比如id属性值 ``` ## 组件的定义和使用 ``` 1. 定义组件 Vue.component('组件标签名', { data () { // 指定内部可变数据 return { count: 0 } }, props: ['title'] // 指定外部传入的可变数据 template: '

    {{title}}--{{count}}

    ' }) 2. 使用组件 <组件标签名 :title="xxx"> 3. 组件的data只能是函数, 不能对象 原则: 一个组件的多个标签实例不能共用一个data对象 如果data配置的是对象, 那就会导致多个标签共用一个data对象 ==> 有问题 如果data配置是函数, 函数调用每次都返回一个新的data对象, 每个标签都是自己的data对象 ==> 可以 ``` # day04 ## 使用vue脚手架创建项目 ``` npm i -g @vue/cli yarn: 全局下载脚手架包和yarn (后面创建项目内部要使用) vue create vue-component: 以纯命令的方式创建项目 vue ui: 以图形界面的方式创建项目 yarn serve: 启动 npm install -g @vue/cli-init: 下载2.x的脚手架包 vue init webpack my-project: 创建项目 3/4脚手架与2脚手架的最大区别: 2的项目的webpack配置是暴露 ==> 可以直接修改, 但也容易改得不好 3/4项目的webpack配置是隐藏 ==> 如果需要修改webpack配置, 在vue.config.js中编写(由脚手架来定) ``` ## 打包运行项目的2种方式 ``` 1. 开发环境运行 命令: yarn serve 本质: 1. 在内存中打包(编译)生成打包文件 2. 启动服务器运行项目 2. 生产环境打包运行 命令: 打包: yarn build 下载服务器包: npm i -g serve 运行: serve dist 本质: 1. 在内存中打包(编译)生成打包文件 2. 将内存中的打包文件保存到本地 3. 将本地打包加载中内存中 4. 启动服务器运行项目 ``` ## 单文件组件的定义与使用 ``` 1. 定义组件: xxx.vue 2. 使用组件 引入 注册 组件标签 3. 创建vm new Vue( render: h => h(App) // 根据指定的App组件创建组件实例对象, 并渲染到页面 ).$mount('#app') ``` # day05 ## 组件化编码的基本流程 ``` 1. 静态页面 2. 拆分界面组件 App Header List Item Footer 3. 实现静态组件页面 4. 实现动态组件 初始化数据动态显示 设计初始化数据 将数据在当前组件或通过props传递后代组件显示 交互: Header: 添加 Item: 移入移出 / 删除 / 勾选 Footer: 显示 / 全选 / 删除所有勾选的 设计初始化数据 数据结构: [{id, title, completed}] 名称(根据数据意义来取名): todos 位置( 保存在哪个组件): 看是哪个组件使用?: 交给它 还是哪些组件使用?: 交给它们共同的父组件 ==> App ``` ## props使用深入 ``` 1. 在父组件中可以通过标签属性向子组件传入数据 2. 在子组件中需要通过props配置声明接收属性数据 写法1: 只指定属性名 props: ['name', 'myAge'] 写法2: 指定属性名和类型 props: { name: String, myAge: Number } 写法3: 指定属性名, 类型, 必要性, 默认值, 校验 props: { name: { type: String, required: true }, myAge: { type: Number, default: 0, validator (value) { return value >=0 } } } 3. 标签名与属性名写法 完全一样 大写变小写, 中间用-连接 标签名不要与原生标签名重名 ``` ## 通过props实现父子间相互通信 ``` 1. 父向子 父组件: 向子组件标签传入标签属性 ==> 属性值必须是非函数 子组件: 通过props声明揽收, 读取属性数据显示 2. 子向父 父组件: 向子组件标签传入标签属性 ==> 属性值是函数 (函数在父组件中) 子组件: 通过props声明揽收, 调用传入的函数, 可以传入参数数据, 数据就从子组件传到了父组件中 3. 问题: 祖孙组件间通信比较麻烦: 必须逐层传递 兄弟组件间通信比较麻烦: 借助父组件传递 ``` ## 相关问题 ``` 移入移出的事件监听 mouseenter与mouseleave: 进入子元素不会触发leave mouseover与mouseout: 进入子元素会触发out 查看问题的基本流程 看有没有报错 ===> 控制台 看数据 ==> vue调试工具 看元素及样式 ==> 检查元素及对应的样式 查看代码 组件化编码的基本原则 数据在哪个组件, 修改/更新数据的函数就应该定义在哪个组件, 其它组件如果要更新这个数据, 只能是想办法调用更新函数来更新这个数据 组件不要直接去修改props中的数据 ``` ## 功能: 关闭浏览再打开访问还能看到最后的样子 ``` 存储数据: 存储哪个数据? todos 什么时候保存? 总是保存最新的数据 ==> 对todos进行深度监视, 在监视的回调中保存 保存在哪里? localStorage 读取数据 什么时候读取: 初始化时就读 ``` # day06 ## 组件间通信1: props ``` props: 实现父子组件间通信 父向子通信: 非函数props 子向父通信: 函数props 不足: 1. 祖孙组件: 必须逐层传递 ==> 麻烦 2. 兄弟组件: 必须借助父组件 ==> 麻烦 ``` ## 组件间通信2: Vue自定义事件 ``` Vue自定义事件实现: 子向父通信 ==> 用来替代函数props 1. 原生DOM事件 1) 绑定事件监听