vue

property 所有的组件都要写到components文件夹中
所有的全局样式 都要写到main.js 入口文件中   
 
想要去掉地址中的 # 也不难,只要更换 vue-router 的另一个模式 history 模式即可做到。
const router = new VueRouter({
  mode: 'history', //去掉url中的#
  routes
})
 
 Vue CLI3--运行单个 *.vue 文件
    1. 安装全局扩展
    npm install -g @vue/cli-service-global
    2. 运行.vue文件
    vue serve 文件夹名
注意: 如果已经安装过可以直接运行 vue serve 文件夹  运行时, 会自动生成一个 node_modules 文件夹
 
JSON.parse(JSON.stringify(row))
JSON.parse('要转换的数据')
JSON.stringify('要转化的数据')
俩个方法的用法差别:
①.JSON.stringify是从一个对象中解析出字符串
②.JSON.parse是从一个字符串中解析出json(键值对)
主要用来解决:
  俩个地方同时调用一个数据 (v-model) 产生的变化 (相当于深拷贝)
 
数据可视化 D3.js
 想要修改vue项目自动开启浏览器 在config下的 index.js里的 module.exprots里的 dev项 修改
 module.exports = {
      dev: {
        host: 'localhost', // 可以被process.env.HOST覆盖 
        port: 3000, // 配置端口号 默认8080 
        autoOpenBrowser: true, // 是否自动打开浏览器 
        errorOverlay: true,
        notifyOnErrors: true, poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- 
     }
 vue ui 可以快速的生成vue项目
 
 
 通过 Vue cli2 初始化项目
通过 vue init webpack 文件名称  创建vue项目()
输入上面命令后,会询问几个选项,根据自己需要填写就可以了。
一、Project name :项目名称,如果不需要就直接回车。注:此处项目名不能使用大写。
二、Project description:项目描述,直接回车
三、Author :作者
四、vue build 构建方式(暂且这么解释)
  两个选择(上下箭头选择,回车即为选定)(是使用阉割版的vue还是使用完整版的vue 第一个是完整版的 第二个是阉割版的)
  1.Runtime + Compiler:recommended for most users
  (译:运行+编译:被推荐给大多数用户)
  2.Runtime-only:about 6KB lighter min+gzip,but templates (or any Vue-specific HTML) are ONLY 
  allowed in .vue files-render functions are required elsewhere
  (译:只运行大约6KB比较轻量的压缩文件,但只允许模板(或任何VUE特定HTML)。VUE文件需要在其他地方呈现函数。翻译不精准,意思大概是选择该构建方式对文件大小有要求)
  这里推荐使用1选项,适合大多数用户的
五、install vue-router?是否安装vue的路由插件,需要就选y,否则就n(以下均遵循此方法)
六、Use ESLint to lint your code?是否使用ESLint检测你的代码?
  (ESLint 是一个语法规则和代码风格的检查工具,可以用来保证写出语法正确、风格统一的代码。)
七、Pick an ESLint preset:选择分支风格
  选项有三个
  1.standard(https://github.com/feross/standard) js的标准风格
  2.Airbnb(https://github.com/airbnb/javascript) JavaScript最合理的方法,这个github地址说是JavaScript最合理的方法
  3.none (configure it yourself) 自己配置
八、Set up unit tests? 是否安装单元测试(暂不详细介绍)
Pick a test runner 选择一个单元测试运行器
选项有三个
1.Jest(Jest是由Facebook发布的开源的、基于Jasmine的JavaScript单元测试框架)
2.Karma and Mocha
3.none
九、Setup e2e tests with Nightwatch(Y/n)?是否安装E2E测试框架NightWatch(E2E,也就是End To End,就是所谓的“用户真实场景”。)
Should we run 'npm install' for you after the project has been created?(译:项目创建后是否要为你运行“npm install”?这里选择包管理工具)
  选项有三个
  yes,use npm(使用npm)
  yes,use yarn(使用yarn)
  no,I will handle that myself(自己配置安装包)
一路回车到此等待安装完毕,会提示接下来的命令行
npm run dev  或者 npm run serve 运行项目
 
所创建的vue框架的文件说明
 
 
 

 另一种方法 Vue cli3初始化项目
vue create 文件名称
 
在控制台运行 vue create 项目名称
会出现如下选项

 

此处有两个选项
Please pick a preset: (Use arrow keys)  // 请选择预设:(使用箭头键) 
default(babel, eslint)   // 默认套餐
Manually select features  // 自己去选择需要的功能,提供更多的特性选择。比如如果想要支持 TypeScript ,就应该选择这一项
  如果选择第二个会出现如下选项

 

 

vue-cli 内置支持了8个功能特性,可以多选:使用方向键在特性选项之间切换,使用空格键选中当前特性,使用 a 键切换选择所有,使用 i 键翻转选项。

对于每一项的功能,此处做个简单描述:
babel  网络
TypeScript 支持使用 TypeScript 书写源码。
Progressive Web App (PWA) Support PWA 支持。
Router 支持 vue-router 。
Vuex 支持 vuex 。
CSS Pre-processors 支持 CSS 预处理器。
Linter / Formatter 支持代码风格检查和格式化。
Unit Testing 支持单元测试。
E2E Testing 支持 E2E 测试。
那么基于开发常见的项目,同时兼顾项目健壮性的原则,本次选择如下特性支持:
 
 ②
Use class-style component syntax?  //使用类样式组件语法?
  这里是让选择在开发 Vue 组件时,要不要使用 class 风格的写法。为了更方便地使用 TypeScript ,此处选择 Y
 Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? 
// 在TypeScript旁边使用Babel(对于现代模式、自动检测的polyfill、transpiling JSX是必需的)?
这个选项的意思是要不要使用 babel 工具自动为转换后的 TypeScript 代码注入 polyfiills 。如果实在搞不清楚具体是什么意思,可以先不用管,直接选择 Y ,进入下一步
④第四个选项
Use history mode for router? (Requires proper server setup for index fallback in production) // 使用路由器的历史模式?(需要为生产中的索引回退设置正确的服务器)
⑤第五个选项
这里就是说我们在项目里面需要支持何种动态样式语言,此处提供了三个选项:(此处选择 less)
 sass/scss
less
stylus  
 
 Pick a unit testing solution:  // 选择单元测试解决方案: 
? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? // 希望在哪里放置Babel、PostCSS、ESLint等的配置。
  In dedicated config files // 专用配置文件中
  In package.json  // 在 package.json中
这一步就是要选择配置文件的位置了。对于 Babel 、 PostCSS 等,都可以有自己的配置文件: .babelrc 、 .postcssrc 等等,同时也可以把配置信息放在 package.json 里面。
此处出于对编辑器( Visual Studio Code )的友好支持(编辑器一般默认会在项目根目录下寻找配置文件),选择把配置文件放在外面,选择 In dedicated config files
? Save this as a preset for future projects?    // 此保存为将来项目的预设?
这个就是问要不要把当前的这一系列选项配置保存起来,方便下一次创建项目时复用。对于 MAC ,保存的配置信息会放在 ~/.vuerc 里面。
 
 
 
 
 
 
 
 
 
 
 mixins 作用: 把外界导入过来的行为,混入到 组件中 mixins 是与data平级的 他是一个数组
mixins: [] // 导入过来的行为
import min from '行为组件'
export default {
mixins: [ min ]
}
 
el: 接收 id和类名 用的
methods:绑定事件用的(用于定义的函数,可以通过 return 来返回函数值。)
data: 要渲染的内容(用于定义属性,实例中有三个属性分别为:site、url、alexa)
exit 终止终端运行
cls 清空终端
 
Vue.js是一套构建用户界面的框架,只关注视图(页面)层的开发
MVC 主要是后端的分层开发思想;把 一个完整的后端项目,分成了三个部分:
Model:(数据层)主要负责 数据库的操作;
View:(视图层)所有前端页面,统称为 View 层
Controller:(业务逻辑层)主要处理对应的业务逻辑;(对于后台来说,这是开发的重点)
MVVM是前端页面的分层开发思想,主要关注于 视图层 分离,也就是说:MVVM把前端的视图层,分为了 三部分 Model, View, ViewModel
Model 是 页面中,需要用到的数据
View 是页面中的HTML结构;
ViewModel 是 一个 中间的调度者,提供了双向数据绑定的概念;
为什么有了MVC还要有MVVM
因为 MVC是后端的开发思想,并没有明确定义前端的页面该如何开发;
MVVM 是前端的页面的开发思想,把每个页面,分成了三个部分,同时 VM 作为 MVVM 的核心,提供了双向数据绑定的概念,前端程序员,不需要手动渲染页面了,
而且,页面数据发送变化,也不需要程序员手动把 数据的变化同步到Model中;这所有的操作,都是 VM 自动完成的!
有了 MVVM 的思想以后,前端只关心 页面交互逻辑,不关心页面如何渲染;
 
 
Vue.js基本代码和MVVM之间的对应关系
  1. 注意:Vue不推荐程序员手动操作DOM元素,所以,在Vue项目中,没有及其变态的需求,一般不要引入jQuery
  2. Vue代码解析执行的步骤:
(1) VM 实例对象,被创建完成之后,会立即解析el指定区域中的所有代码
(2) VM在解析el区域中所有代码的时候,会把data中的数据 按需添加到页面指定的区域
  1. 注意:每当vm实例对象 监听到data中的数据发生了变化,就会立即 重新解析执行el区域内所有的代码
 
Vue中的命令是:
定义: vue中通过一些特殊的语法,扩展HTML的功能
将来创建Vue实例的时候,Vue会把这些指令都进行解析,从而 根据不同的指令 执行不同的操作、渲染不同的结果
 
Vue指令:
插值表达式:插值表达式 {{}}   在指定的位置动态插入内容
<div id="app">{{msg}}</div>
 
v-cloak 解决插值表达式闪烁问题
当网络比较卡的时候,我们可以为最外层的div元素 添加 v-cloak 防止用户看到插值表达式
注意: 必须写一个css样式 [v-cloak]{ display:none} 不然没有效果
 
v-text 在元素的属性节点上 添加v-text 如:<p v-text="msg"></p> // 覆盖原有内容
不会解析标签
v-text 与 {{}}区别
是否覆盖内容
指令闪烁问题
 v-once 只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。
 
 
 
 
 
v-html在元素的属性节点上 添加v-htmll如:<p v-html="msg"></p> // 覆盖原有内容
会解析标签
v-html 与 {{}}区别
是否覆盖内容
指令闪烁问题
 
v-bind: : 属性绑定
如:<button v-bind:title="titleStr">按钮</button>
应用场景:如果元素的属性值,需要动态地进行绑定,则需要使用v-bind: 指令
v-bind: 可以简写为 :
 
v-model实现双向数据绑定(v-model 指令用来在 input、select、text、checkbox、radio 等表单控件元素上创建双向数据绑定,根据表单上的值,自动更新绑定的元素的值。
可以把页面上数据的变化,自动同步更新到VM实例的data中
<input v-model="msg" /> // 等同于 <input :value="msg" @input="msg = $event.target.value" />
解释:
       $event 指代当前触发的事件对象。
       $event.target 指代当前触发的事件对象的dom
  $event.target.value 就是当前dom的value值
      在@input方法中,
        value => msg
        在: value中:
        msg => value
        如此,形成了一个闭环,也就是所说的数据的双向绑定。
 
v-model的修饰符
 v-model.lazy 只有在input输入框按回车键的时候和input失去焦点的时候才触发v-model
    v-model.trim 将用户输入的前后的空格去掉
    v-model.number 将用户输入的字符串转换成number
 
 
v-bind:的区别:
v-bind: 只能实现单向的数据同步 data ---> 页面;
v-model 可以实现双向的数据同步 data <--> 页面;
 
注意:
v-model 只能 和 表单元素 配合使用,例如 input、select、textarea 等;
v-model 是 Vue 中 唯一支持 双向数据绑定的指令;
 
vue中使用 class样式
类名数组中使用三元表达式,按需为元素添加某些类名
不要让vue的实例对象 的el指向html和boty标签
<p :class=”[flag?’light’:’dark’]”></p> // 如果flag为真类名为light 为假类名为dark
 
 
Vue指令值v-for和:key 属性
语法:
<li v-for=”循环的item项,索引 in 数组名”:key=””></li>
只要用到了 v-for指令,那么必须带上 :key属性(只要有状态的情况下 必须带上 :key)
推荐,直接把item.id 当作key的值
在真是的项目中,调用API接口拿到的数据 都会包含ID 的
如:<li v-for="(item, key, index) in arr" :key="item.id">
当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用 “就地复用” 策略。如果数据项的顺序被改变,Vue将不是移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性。
 key的作用是为了高效的更新虚拟DOM
 
Vue 指令 v-if和v-show
v-if 是动态的移除或者显示 判断的值如果是true 的话 显示  false 移除
v-show 是控制 display属性
v-if和v-show的作用,都是切换界面上元素的显示或隐藏的
一般来说,v-if有更高的切换消耗 二 v-show有更高的初始化渲染消耗
因此,如果需要频繁切换 v-show比较好 如果在运行时条件不太可能改变 v-if比较好
 

v-on: 事件绑定
v-on的作用,是为HTML元素绑定事件的处理函数 如:
<input type="button" value="按钮" v-on:click="事件处理函数名" />
v-on:click 可以简写为 @click
在事件定义时, 写方法时省略了小括号,但是方法本身是需要一个参数的,这个时候, vue会默认将浏览器产生的event事件对象作为参数传入到方法
方法定义时我们需要event对象同时用需要其他参数
在调用方法是,手动获取到浏览器参数的event对象 $event 
所有的事件在省略小括号的情况下, 系统会把event默认传递过去
 
 当methods中定义方法,以供@click调用时,需要主要参数问题:
①如果不需要额外的参数,那么方法后面的 () 可以省略
②如果方法本身有一个参数,那么会默认将原生事件 event参数传递过来去
③如果需要传入某个参数, 同时需要 event 时, 可以通过 $event传入事件
  
在所有的绑定事件中 事件处理函数都有一个默认的 event 参数
event.target始终指向事件发生时的元素,而event.currentTarget指向事件所绑定的元素
 
 
事件修饰符
.prevent 阻止 submit提交、A标签默认行为跳转行为 (@click.prevent = "事件") 常用  对应event.preventDafault 阻止默认事件
.once 只触发一次
.stop 阻止冒泡 对应event.stopPropagation 阻止事件冒泡
.self 只有在当前元素上触发事件的时候,才会调用处理函数(不会阻止冒泡) 只有event.target 为自身才触发事件
.passive   滚动事件的默认行为(即滚动行为) 将会立即触发 而不会等待`onScroll` 完成 这其中包含`event.preventDefault()` 的情况
 .native  就是在父组件中给子组件绑定一个原生的事件,就将子组件变成了普通的HTML标签,不加'. native'事件是无法触  发的。
.self的理解
  我们知道在一般情况下,e.target总是指向最内层的元素 所以如果父元素设置了.self 修饰符 那么他在点击子元素时,并不会触发被修饰的事件;只有点击没有子元素的空白区域时,才会触发被修饰的事件
  官方文档的一个提示
  使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v - on: click.prevent.self 会阻止所有的点击,而 v - on: click.self.prevent 只会阻止对元素自身的点击。
事件修饰符可以连续多次调用
阻止跳转默认行为
只会阻止一次
 
按键修饰符(键盘按键) 按键修饰最好配合 input 输入框使用
按键修饰符都是配合文本输入框使用
.eneter  按回车键 才会触发
.tab 按tab键 才会触发
.esc  只有按ESC键的时候才会触发
.space 空格键
......... 所有键盘按钮都可以
@keyup.enter 按键盘回车才会触发
@keyup.键盘按键
 
通过全局 config.keyGodes 对象自定义按键修饰符别名
Vue.config.keyGodes.按键名 = 自定义按键
例: Vue.config.keyGodes.f2 = 112 
  
 
 
过滤器
概念:过滤器本质上就是一个函数,可以被用作一些常见的文本格式化
过滤器只可以用在俩个地方: mustache(插值表达式) 和 v-bind:( 属性绑定)中
过滤器应该被添加在JavaScript表达式的尾部,有 管道符( | ) 指示
 
任何vue实例都可以调用全局过滤器
全局过滤器需要Vue.filter()来定义
私有过滤器需要定义到每个实例的 filters 属性中
私有过滤器只能被当前所属实例调用
 
全局过滤器
使用全局过滤器的语法: {{ msg |过滤器名称}}
定义全局过滤器的语法
html语法:
<h1>{{msg | dateFromat(/*传递的参数*/)}}</h1>
过滤器语法:
Vue.filter(‘过滤器的名称’,function(originVal,pattern){
  /* originVal 管道符前面传递过来的值 */
  /* 传递的参数 */
  /* 对数据进行处理的过程 在这个function中,最后必须return一个处理的结果,否则就是一个非法的过滤器 */
})
 
注意:过滤器的处理函数,
形参列表中的第一个参数,永远都是 管道符 前面传递过来的值
       第二个参数是传的参数
过滤器不会修改原来的值
 // originVal 插值表达式  pattern 传入的参数
 
使用过滤器的注意事项:
1.如果想拿管道符前面的值,通过function的第一个形参来拿
2.过滤器中,一定要返回一个处理的结果,否则就是一个无效的过滤器
3.在调用过滤器的时候,直接通过( ) 调用就能传参,从过滤器处理函数的第二个参数开始接收传递过来的参数
4.可以多次使用 管道符(|) 一次调用多个过滤器 执行顺序是 从左往右执行
5.在一个标准的过滤器中, 最后一定要 return 返回值, 否则就是一个非法的过滤器

扩展
// 字符串新方法 string.prototype.padStart(填充完毕之后的总长度,以什么字符串进行填充) // 从前面添加
// 字符串新方法 string.prototype.padEnd(填充完毕之后的总长度,以什么字符串进行填充) // 从后面添加
可以给一位数时间自动补齐 0
使用Vue.filter创建的是全局过来器
私有过滤器 与el data 平级 创建一个 filters
私有过滤器
Vue语法:
var vm = new Vue({
  el: '#app',
  data: {},
  filters: {
  // 这是 古老的 ES3写法
  过滤器的名称: function(originVal){},
  // 这是最新的ES6写法【推荐】 
  // '过滤器名称':'过滤器处理函数'
  过滤器的名称(originVal){ return 处理的结果 } } })

filters('my-filter', function (value) { // 返回处理后的值 })
 
 
 注意:过滤器查找顺序问题,就近原则
Vue.$mount( ) el用法相同 在没有el的时候 用Vue.$mount() 动态挂载实例对象
语法: Vue.$mount(“选择器- 指定要控制的区域”)
Vue.$mount( )  手动控制要指定的区域
  <div id="app">
    {{msg}}
  </div>
  <script>
    const vm = new Vue({
      data: {
        msg: 'hello'
      }
    })
    vm.$mount('#app')
  </script>
 
template 属性指定模板
templatedata平级 ,会替换到el所指定的区域
如果在new Vue实例的时候,既指定了el 又指定了template,则会把template指定的模板结构,替换掉el的模板结构 
<div id="app">
    <h1>{{msg}}</h1>
  </div>
  <script>
    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {
        msg: 'hello'
      },
      template: '<h6>哈哈哈</h6>'
    });
  </script>
 
 
什么是生命周期
生命周期:实例的生命周期,就是一个阶段,从创建到运行再到销毁的阶段
生命周期函数:在实例的生命周期中,在特地阶段执行的一些特定事件,这些事件叫做生命周期函数
  生命周期函数又叫 --生命周期钩子--生命周期事件
 
 
生命周期函数分类
Vue的三个阶段(创建阶段->运行阶段->销毁阶段)
生命周期:每个Vue实例,从创建到运行 再到销毁的整个阶段,就是完整的生命周期
生命周期函数: 在每个实例的生命周期中,都会依次按顺序调用固定个数的函数,这些函数,叫做生命周期函数
生命周期函数是由框架开发人员预先定义好的,每个实例在创建,运行,销毁的过程中,都后悔依次顺序 自动调用这些函数
程序员要做的事情就是在这些固定的函数中,左自己指定的业务处理就行
创建期间的生命周期函数:(特点:每个实例一辈子只执行一次)
  1、beforeCreate:创建之前,此时 data 和 methods 尚未初始化 (当执行到 beforeCreate生命周期函数时,当前Vue实例的data和methods方法,都还没有初始化完成,因此,这个函数对于我们没有太大的意义)
  2、created 第一个重要的函数,此时,data 和 methods 已经创建好了,可以被访问了 (当执行到created生命周期函数的时候,实例的data数据和methods方法,都已经被初始化完毕,可以被正常访问 [一般首屏数据的Ajax请求,都要在created中发起ajax])
  3、beforeMount:挂载模板结构之前,此时,页面还没有被渲染到浏览器中;(此时,浏览器中的页面还是假页面,并不是真正带有数据的页面,在这个函数里插值表达式还没有解析好)
  4、mounted 第二个重要的函数,此时,页面刚被渲染出来;如果要操作DOM元素,最好在这个阶段 (第三方UI插件如果需要初始化 一定要写在mounted中
        创建页面结束
运行期间的生命周期函数:(特点:按需被调用 至少0次,最多N次)
  5、beforeUpdate:将要根据最新的data数据,从新解析所有指令,从而重新渲染浏览器页面,此时 数据是最新的,而页面是旧的
    (中间会重新根据最新的data数据,解析所有指令,从而渲染并得到最新的页面,然后把渲染出来的新页面 替换到 浏览器中)
  6、updated:只要触发了updated,就说明,页面和数据都是最新的
销毁期间的生命周期函数:(特点:每个实例一辈子只执行一次)
  7、beforeDestroy:销毁之前,实例还正常可用
  8、destroyed:销毁之后,实例已经不工作了
 
      beforeCreate(创建前),
      created(创建后),[主要发起Ajax 获取页面的首屏数据]
      beforeMount(载入前),
      mounted(载入后),[主要用来初始化第三方UI插件]
      beforeUpdate(更新前),
      updated(更新后),
      beforeDestroy(销毁前),
      destroyed(销毁后)

vue的生命周期(开始创建、初始化数据、编译模板、挂载Dom、渲染、更新、渲染、卸载)主要分为八个阶段:

beforeCreate  data $el 都没有初始化 全部为 undefined

created data 初始化完成,但 $el 没有初始化

beforeMount data $el 均已存在,但 DOM 为虚拟DOM 仍未完全加载 eg<div>{{message}}</div>

mounted data $el 均已存在,并且 DOM 加载完成 ,完成挂载

data中数据发生改变时触发update相关函数

beforeUpdate 渲染完成,并监测到data发生变化,在变化的数据重新渲染视图之前会触发,这也是重新渲染之前最后修改数据的机会

updated 监测到data发生变化,并完成渲染更新视图之后触发

beforeDestory 实例销毁之前调用 , 实例仍然完全可用。

destroyed 实例销毁后调用。调用后,实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

另外还有 keep-alive 独有的生命周期,分别为 activated deactivated 。用 keep-alive 包裹的组件在切换时不会进行销毁,而是缓存到内存中并执行 deactivated 钩子函数,命中缓存渲染后会执行 activated钩子函数。

vue生命周期的应用场景:

beforeCreate:在new一个vue实例后,只有一些默认的生命周期钩子和默认事件,其他的东西都还没创建。在beforeCreate生命周期执行的时候,data和methods中的数据都还没有初始化。不能在这个阶段使用data中的数据和methods中的方法
create:data 和 methods都已经被初始化好了,如果要调用 methods 中的方法,或者操作 data 中的数据,最早可以在这个阶段中操作
beforeMount:执行到这个钩子的时候,在内存中已经编译好了模板了,但是还没有挂载到页面中,此时,页面还是旧的
mounted:执行到这个钩子的时候,就表示Vue实例已经初始化完成了。此时组件脱离了创建阶段,进入到了运行阶段。 如果我们想要通过插件操作页面上的DOM节点,最早可以在和这个阶段中进行
beforeUpdate: 当执行这个钩子时,页面中的显示的数据还是旧的,data中的数据是更新后的, 页面还没有和最新的数据保持同步
updated:页面显示的数据和data中的数据已经保持同步了,都是最新的
beforeDestory:Vue实例从运行阶段进入到了销毁阶段,这个时候上所有的 data 和 methods , 指令, 过滤器 ……都是处于可用状态。还没有真正被销毁
destroyed: 这个时候上所有的 data 和 methods , 指令, 过滤器 ……都是处于不可用状态。组件已经被销毁了。

beforeCreate 可以在此时加一些loading效果,在created时进行移除

created 需要异步请求数据的方法可以在此时执行,完成数据的初始化

mounted 当需要操作dom的时候执行,可以配合$.nextTick 使用进行单一事件对数据的更新后更新dom

updated 当数据更新需要做统一业务处理的时候使用

 
下面是图解
 
Promise 的含义
Promise是构造函数, 可以被new
new 出来的 Promise 实例对象,就表示一个异步操作
Promise.prototype 上, 包含.then() 和 .catch() 俩个方法
 
 
Promise 是异步编程的一种解决方案,比传统的解决方案回调函数和事件--更合理和更强大。它由社区最早提出和实现,ES6将其写进了语言标准,统一了语法,原生提供了Promise
所谓Promise ,简单说就是一个容器,里面保存着某个未来才回结束的事件(通常是一个异步操作)的结果。从语法上说,Promise是一个对象,从它可以获取异步操作的消息。 
Promise 对象的状态不受外界影响
 
Promise 概念:Promise ES6中的新语法,Promise是一个构造函数,每一个new出来的Promise实例对象,都代表一个异步操作
作用: 解决了回调地狱的问题
回调地狱,值得是回调函数中,嵌套回调函数的代码形式;如果嵌套的层级很深,就是回调地狱
回调地狱,不利于代码的阅读、维护和后期的扩展
 
创建形式上的异步操作
const p = new Promise()
 
创建具体的异步操作
const p =new Promise(function(success,error){// 在这和function中定义具体的异步操作})
success:是成功的回调  .then()的第一个function
error:是失败的回调   .then()的第二个function
 
// 1. Promise 是构造函数,可以被new;
// 2. new 出来的 Promise 实例对象,就表示 一个异步操作;
// 3. Promise.prototype 上,包含了 .then() 和 .catch() 两个方法;
  Promise.prototype.then()方法的作用,是为这个异步操作,预先指定 成功和失败的回调函数
  
p.then(
    function(success){/* 成功的回调函数 */},
    function(error){/* 失败的回调函数 */}
)
在使用Promise的时候,如果要捕获错误异常,推荐使用 .catch()
// 4. const p = new Promise() 这行代码,表示创建了一个【形式上的异步操作】;
// 5. const p = new Promise(function(){ /* 具体的异步操作 */ }) 在 new Promise() 的时候,传递的 function 函数,就表示一个具体的异步操作;你可以在 function 中,读文件、也可以 发Ajax;
// 总结:只要 new 了一个具体的异步操作,这个异步操作被创建的一瞬间,就会立即执行;
// 注意:在使用 .then() 方法的时候,失败的回调函数可以被省略;但是成功的回调必须要传递;
// 推荐:在使用 promise 的使用,如果要捕获错误异常了,直接使用 .catch() 就行
 
async await的作用
在使用 Promise 的时候最好使用async 
ES7中的asyncawait可以简化Promise调用,提高Promise代码的阅读性和理解性
async 是一个修饰符, 只能用来修饰方法;被async 修饰的方法,就是一个异步方法
await 只能用在被 async修饰的方法中 同时,await是用来修饰Promise实例对象的 要加在 Promise 之前
注意:async修饰的方法中,在遇到 第一个await之前所有的代码都是同步执行的, 直到 遇到第一个await开始,其他的所有代码,都是以异步形式来执行的
 
  
安装: npm i axios
// 为 axios 挂载 全局的请求根路径
axios.defaults.baseURL = '挂载的地址'
// 把axios 挂载到 vue上  调用名是$http
Vue.prototype.$http = axios
axios只支持getpost请求,无法发起JSONP请求
如果涉及到JSONP请求,可以让后端启用cors跨域资源共享即可
 
Vue中,还可以使用 vue-resource发起数据请求
vue-resource支持 getpostjsonp请求【但是,Vue官方不推荐使用这个包了】
 
只要导入了axios包,在window全局 就多了一个 axios成员
使用axios.get() axios.post() 发送请求
axios.get(‘请求的地址’,{params{/* get 类型的参数 */}}) 
params是添加到url的请求字符串中的,用于get请求
axios.post(‘请求的地址’,{参数:  })
用这个插件发送请求
最好是先把 axios挂载到 Vue
this.$http.get(‘请求地址’)
this.$http.post(‘请求地址’,{要提交的数据})
 
拦截器
 
问题
解决方法
  // 全局配置 axios 的 request 拦截器 
axios.interceptors.request.use(config => { 
    // 通过拦截request请求,主动为 请求头,追加新属性 Authorization,等于 token 值 
  config.headers.Authorization = window.sessionStorage.getItem('token')
  return config
})

 

 
  
Vue动画
动画能够增加页面趣味性,目的是为了让永辉更好的理解页面的功能
注意: Vue中的动画,都是简单的过渡动画,并不会有CSS那么炫酷
  table 不知道过渡效果
 
Vue中的动画的基本介绍
每个动画分为两个部分 : 入场动画 和出场动画
入场动画分为两个时间点和一个时间段
v-enter入场前的样式
v-enter-to入场完成以后的样式
v-enter-active入场的时间段
离场时候Vue也把动画分为两个时间点和一个时间段
v-leave离场之间的样式
v-leave-to离场完成以后的样式
v-leace-active离场的时间段
 
元素在标准流中的样式,就是入场动画的终点状态,同时也是离场动画的起始状态
使用过渡类名
把需要添加动画的元素,使用v-if或者v-show进行控制
把需要添加动画的元素,使用Vue提供的元素 <transition></transition>包裹起来
(1) 如果transition没有显示定义的name属性,那么 它默认的name值为 v
(2) 可以自己定义name 值  定义好后只要把 入场和离场的 v 该成 自己定义的就可以了
(3) transition 添加两个属性: enter-active-class  和  leave-active-class  为需要过渡的元素 ,添加class=”animated” 类名 会有不同要是的动画效果 : 抖动 跳动 ......等等样式 这个需要自己查询官方文档
 
添加两组类
.v-enter,
.v-leave-to{
    opacity: 0;
    transform: translateX(100px);
}
 
.v-enter-active,
.v-leave-active{
   transition: all 0.5s ease;
}
 
在用v-for 循环渲染的元素,添加 :key属性
v-for循环渲染的元素外层,包裹 <transition-group></transition-group>标签
 
列表的排序过渡
<transition-group> 组件还有一个特殊之处。步进可以进入和离开动画,还可以改变定位。要使用这个新功能只需要理解新增 v-move特性,它会在元素的改变定位的过程中应用
v-movev-leave-active 结合使用,能够让列表的过渡更加平缓柔和
/*控制要被删除的元素,脱离标准流*/
.v-leave-active{
  position: absolute;
}
 
/*控制后续的元素,通过过渡位移到目标位置*/
.v-move{
  transition: all 0.8s ease;
}
 
在网页中常引用的静态资源有:
 
样式表
.css  .less   .scss
 
JS文件
.js  .ts
 
图片
.jpg/.jpeg .png .gif .bmp .webp【webp的图片,在苹果手机的浏览器中显示不出来】
 
字体文件
.ttf .eot .woff .woff2 .svg
 
模板文件
.vue .jsx
 
网页中引入的静态资源多了以后的问题:
对网页性能不友好: 要发起很多的静态资源的请求,降低页面的加载效率 ,用户体验差
对程序开发不友好: 前端程序员要处理复杂的文件之间的依赖关系
 
对于JS文件或者CSS文件,可以合并和压缩; 小图片适合转 base64格式的编码
通过一些工具,让工具自动维护文件之间的一览关系
 
webpack
webpack 前端项目的构建工具;前端的项目 都是基于 webpack进行 构建和运行的
如果项目中使用webpack进行构建,我们可以书写高级的ES代码;且不用考虑兼容问题
webpack能够优化项目的性能, 比如合并。压缩文件等
基于webpack 程序员可以把 自己的开发重心放到功能上
 
webpack非常适合于单页面应用程序结合使用
不太适合与多页面的普通网站结合使用
 
在项目中安装和配置webpack
webpack是前端的一个工具,这个工具 可以从NPM官网上下载到本地上使用
 
新建一个项目的空白目录,并在终端中 cd 到目录的根目录 执行 npm init -y 初始化项目
装包 运行 npm i webpack webpack-cli -D 安装项目构建所需的 webpack
在打开package.json文件, 在scripts节点中 新增一个 dev 的节点;(不一定是dev 名字可以根据需要填写) dev  是 development的简写 开发的意思
"scripts": {
    "test": "echo "Error: no test specified" && exit 1",
    "dev": "webpack"
  },
4.在项目根目录中 新建一个 webpack.config.js 配置文件
// 这是 使用 Node 语法, 向外导出一个 配置对象
注意webpack.config.js 是webpack 的配置文件 webpack在运行和打包的时候,会优先读取这个配置文件中 导出的配置对象,根据用户指定的配置对象,来进行项目的编译
默认在webpack 4.x的版本中, 要打包的文件路径是scr下的index.js ,文件的输出路径是dist下的main.js
Webpack的配置文件中,支持使用module.exports 语法,因为webpack这个工具 就是基于node创建的
注意: webpack.config.js 是webpack的配置文件
webpack 在运行和打包的时候,会优先读取这个配置文件中导出的配置对象
根据 用户指定的配置对象来进行项目的编译
webpack是基于node创建出来的
默认在webpack 4.x的版本中,要打包的文件路径是 src->index.js->文件输出路径是dist->main.js
module.exports = {
// 注意:在webpack的配置文件中,mode选项是必须要有的
// 而且在开发阶段一定要配置成development模式
// 只有项目要上线了 才会配置成production 模式
    mode: 'production' // production(没有压缩过的文件) 产品 development(压缩过的文件) 开发
}} 
5.在根目录中,新增一个src目录,并且 在src目录中 新建一个 index.js文件 作为webpack构建的入口;会把打包好的文件输出到 dist 自动建立一个 main.js
6.在终端中,直接运行 npm run dev (或者 npm run serve)启动webpack进行项目构建
 
实现webpack的实时打包构建
借助 webpack-dev-sever 这个工具,能够实现webpack的实时打包构建
运行 npm i webpack-dev-server -D 安装包
打开package.json文件,把scripts节点下的dev脚本,修改为如下配置
"scripts": {
    "test": "echo "Error: no test specified" && exit 1",
    "dev": "webpack-dev-server"
  },

修改index.html文件中的 scriptsrc,让src指向内存中根据目录下的../dist/main.js
<script src=”../dist/main.js”></script>
 实现webpack的实时打包构建
借助于webpack-dev-sever这个工具,能够实现webpack的实时打包构建
运行 `npm i webpack-dev-server -D` 安装包
打开package.json文件,把scripts节点下的dev脚本,修改为:
"scripts": {
    "test": "echo "Error: no test specified" && exit 1",
"dev": "webpack-dev-server"
 
 
 
使用html-webpack-plugin插件配置启动页面
1、装包 npm i html-webpack-plugin -D
2、在webpack.config.js中,导入插件
 
// 导入 html-webpack-plugin,从而帮我们自动把 打包好的 main.js 注入到 index.html 页面中
// 同时,html-webpack-plugin 可以把 磁盘上的 index.html 页面,复制一份并托管到 内存中;
const HtmlPlugin = require('html-webpack-plugin')
const htmlPlugin = new HtmlPlugin({
  // 传递一个配置对象
  template: './src/index.html', //(要复制哪个文件,需要给定一个路径) 指定路径,表示 要根据哪个物理磁盘上的页面,生成内存中的页面
  filename: 'index.html' //(生成新文件的名称 默认会把生成的新文件存放到根路径中,生成的文件也是虚拟的,看不见) 指定,内存中生成的页面的名称
})
   
htmlPlugin 的两个功能:
  1.把template指定的模板页面 复制一份 当做虚拟index.html存放到项目的根目录中
  2.把打包好的 main.js注入到 index.html页面中 ,就不需要手动的引入 main.js文件了
3、把创建好的htmlPlugin对象,挂载到 plugins数组中
 
// webpack 这个构建工具,是基于 Node.js 开发出来的一个前端工具
module.exports = {
  mode: 'development', // 当前处于开发模式
  plugins: [htmlPlugin] // 插件数组
}

   
实现自动打开浏览器、热更新和配置浏览器的默认端口号 记得写在package.json文件的 dev
--open 自动打开浏览器
--host 配置IP地址
--port 配置端口号
--hot 热更新;最新的代码,一打补丁的形式 ,替换到页面上 加快编译的速度
--progress 展示编译的进度
--compress 对网络中传输的文件进行压缩,提高传输效率
"scripts": {
     "test": "echo "Error: no test specified" && exit 1", 
    "dev": "webpack-dev-server --open --port 80 --hot",
     "build": "webpack" 
},
 
 
 
 
ES6 模块化
CommonJS的导入和导出
module.export = {导出的对象} // 导出
let {flag} = require('文件路径')  // 导入
 
 
默认导入(import)的语法:
方法一:
 把文件中的所有内容导出
import  接收名称 from ‘ 模板名称’  // 如: jQuery
import jQuery from 'jQuery'

方法二:
 导出指定的方法或者参数
import {参数或者方法,....} from '模板名称'
import { method,....} from '模板名称'
方法三: 
import * as 自定义名称 from '模板名称'
import * as aaa from '模板名称'

默认导出的语法:注意: 默认导出的成员,在使用import 导入的时候, 可以使用任意合法的成员名称来接收

export default { /*要导出的成员,多个用逗号隔开*/}
注意:在一个模块中,只能使用唯一 一次 export default{} 一个以上就会报错
 
按需求导入(import)和导出(export)
按需导入语法:
import { 成员名称 } from '模块名称'
如果要给导入的文件重命名 不要用 “ :” 要用as
按需导出语法:
方法一:
export var a = 10
..........
方法二:
export {a,.......}

 

 export default 与 export的区别
  1、export与export default均可用于导出常量、函数、文件、模块等
  2、你可以在其它文件或模块中通过import+(常量 | 函数 | 文件 | 模块)名的方式,将其导入,以便能够对其进行使用
  3、在一个文件或模块中,export、import可以有多个,export default仅有一个
  4、通过export方式导出,在导入时要加{ },export default则不需要
 
 
如果是HTML文件 在引入 JS 文件时, 给 script 加一个 type="module" 这样就不会出现变量名重复定义
 <script src="./bbb.js" type="module"></script>
 <script src="./aaa.js" type="module"></script>

上述引用 如果直接调用其中的参数 会出现下列错误

 

 

 

打包处理非js文件

使用webpack打包css文件

运行 cnpm i style-loader css-loader -D
打开 webpack.config.js 配置文件,在 module -> rules 数组中,新增处理 css 样式表的loader规则:
module: {
// 所有 非.js 结尾的第三方文件类型,都可以在 module 节点中进行配置
// rules 是匹配规则,如果 webpack 在打包项目的时候,发现,某些 文件的后缀名是 非 .js 结尾的
// webpack 默认处理不了,此时,webpack 查找 配置文件中的 module -> rules 规则数组;
rules: [ { test: /.css$/, use: ['style-loader', 'css-loader'] } ] }

  

使用webpack打包less文件

运行 cnpm i less-loader less -D
在 webpack 的配置文件中,新增一个 rules 规则来 处理 less 文件:
{ test: /.less$/, use: ['style-loader', 'css-loader', 'less-loader'] }

  

使用webpack处理css中的路径

运行 cnpm i url-loader file-loader -D
在 webpack 的配置文件中,新增一个 rules 规则来 处理 图片 文件:
// ?limit:只有小于limit大小的图片,才会被转为 base64单位是字节    
{ test: /.jpg|png|gif|bmp$/, use: 'url-loader' } 
Bype{ test: /.jpg|png|gif|bmp$/, use: 'url-loader?limit=字节' }

  
使用babel处理高级JS语法
之前说过,webpack 默认能够打包处理一些ES6中的高级语法;但是,webpack 并不能处理所有的高级ES6、ES7语法;
运行两套命令,去安装相关的 loader:
运行 cnpm i babel-core babel-loader babel-plugin-transform-runtime -D
运行 cnpm i babel-preset-env babel-preset-stage-0 -D
添加 babel-loader 配置项:
// 注意:在配置 babel-loader 的时候,一定要添加 exclude 排除项,把 node_modules 目录排除
// 这样,只让 babel-loader 转换 程序员 自己手写的 JS 代码;
// 好处:1. 能够提高编译的转换效率; 2. 能够防止不必要的报错!
{ test: /.js$/, use: 'babel-loader', exclude: /node_modules/ }
在项目根目录中,添加 .babelrc 配置文件:
{ "presets": ["env", "stage-0"], "plugins": ["transform-runtime"]}
 
在项目开发中,不会让腻手动配置    
先装一个npm i vue-cli -g 的全局包
在安装Vue init webpack项目名称 (没有引号)
会自动生成(下载)所有模板  第1个到 第7个都是 默认安装 第八个和第九个不装
就会自动安装好上边的所有配置  安装好后既可以在src 中写代码了
 
 
 
webpack中安装和配置vue
运行npm i vue -S 把vue安装到项目依赖中
在index.js中使用import导入 vue模块
 
import vue from ‘vue’
 
index.html中创建将来要被vm实例控制的div 
 基于webpack的vue项目中,按照如上操作会报错
  1. 是因为使用import导入的vue 模板,导入的并不是功能最全的vue包,而是删减版的
  2. 删减版的vue包中功能很少,目的是为了减小vue的体积,因为文件越小,网络请求越快
  3. 想要让import导入最全的vue包 把import vue from ‘vue’,改成 import from ‘vue/dist/vue.js’
注意:在学习阶段可以再试使用import最全的vue包 开发是一定要用删减版的
 
 模块化和组件化的概念
  http://mint-ui.github.io/#!/zh-cn mint-ui 基于Vue.js 的移动端组件库
  https://element.eleme.cn/2.0/#/zh-CN  Element,一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库
 模块化:是从代码的角度分析问题,把可以复用的代码 抽离为单独的模板 
      模块化的好:提供模块作用域的概念 防止全局污染
      提高代码的复用率 方便程序员之间的代码共享
组件化:组件化是从网页UI的角度进行分析问题的,把网页中可以复用的UI结构 抽离为单独的组件
    组件化的好处: 方便 UI 结构的重用
    随着项目的开发的深入,手中可用的组件会越来越多
    可以直接使用第三方封装好的组件库
    组件化能够让程序员更专注于自己的业务逻辑
 注意:每个组件必须有唯一的根元素进行包裹
 
简单来说就是: 我们将一个完整的页面分成很多个组件
        每个组件都用于实现页面的一个功能块
        而每个组件又可以进行细分
注册组件的基本步骤
  1. 创建组件构造器
    调用 Vue.extend()方法创建组件构造器
  2. 注册组件
    调用Vue.component()方法注册组件
  3. 使用组件
    在vue实例的作用范围内使用组件
 
 以上俩个都可以
 
定义全局组件
语法: Vue.component(‘组件的名称’,{组件的配置对象})
例:
// 组件名称最好是my-名称
Vue.component('my-com1',{
// 通过template属性,来指定当前组件的UI结构 template: '
<div>这是自定义组件 my-com1</div>' })
 
 
 
在组件的配置对象中,使用template属性指定当前组件要渲染的模板结构
使用组件的语法
组件名称 以标签的形式 引入到页面是上 就可以了 (记得把组件名称添加到<div id=”app”>里面)
例:
<
div id="app"> <my-com1></my-com1> </div>
 
 
 
注意:
  从更抽象的角度来说,每个组件就相当于是一个 自定义的元素

  组件中的DOM结构 且只能有唯一的根元素 进行包裹, 下面的会报错(在template属性里面只能有唯一的元素包裹)

例: Vue.component('my-com1',{ template: '<div>这是自定义组件 my-com1</div><p>捣乱的</p>' })
 
 
组件中定义 data 数据  methods方法  以及生命周期函数
可以认为: 组件是特殊的vue 实例
组件和实例 相同和区别
  1. 在组件中的data必须是一个function并且return 一个对象出去;vue实例中 data既可以是一个对象,也可以是方法
  2. 在组件中,直接通过template属性来指定组件的UI结构
  3. 而在vue实例中,通过el属性指定实例控制的区域,但在实例中也可以通过template指定
Vue.compotrmt('my-com1',{ template:' <div>这是自定义组件my-com1</div> ', data:function() { rentrn {
    msg:'hello'
    } } }
 
为什么组件中的data属性必须定义为方法并且返回一个对象
在组件中的data属性必须定义为一个方法并返回一个对象
因为这样 能够保证每次创建的组件案例 都是自己的一块唯一的数据内存,防止组件之间数据的干扰
 
使用components 属性定义私有的子组件
在每个实例中,和 el data methods filters 平级 可以使用components属性,注册当前实例的私有子组件
vue.component( ) 注册的全局组件不同 私有组件 只能在当前实例控制的区域内使用(其余用法都一样)
components:{ '组件名称':配置对象 }
 
 
 
 
.vue为后缀名的文件夹的结果说明
每个.vue 文件 都是一个vue组件 他有三部分组成
template 写结构
script 行为样式
style 写样式结构的
Visual Studio Code要想有提示必须要安装这两个插件
 
webpack中配置 .vue 组件网页的解析
  1. 运行 npm i vue-loader vue-template-compiler -D
  2. 在添加webpack.config.js文件中的 rules节点上添加匹配规则
{test:/.vue$/,use:’vue-loader’}
 
  1. webpack.config.js中导入并配置插件
//导入插件
const VueLoaderPlugin = require('vue-loader/lib/plugin')
// new 一个插件的实例对象
const vuePlugin = new VueLoaderPlugin()
// new 出来的插件实例对象,挂载到 `plugins` 节点中:
plugins: [...其它插件, vuePlugin]
 

导入并使用 .vue 组件的两种方式

全局注册 .vue 文件:
index.js 中导入 .vue 组件
使用 Vue.component() 把导入的 .vue 组件,注册为全局组件
 
私有注册 .vue 文件:
定义两个独立的组件 a.vue  c.vue
a.vue 组件中,导入 c.vue 文件,并使用 a.vue 组件的 components 属性,把 c.vue 注册为自己的私有子组件
//1. c.vue中导入 a.vue
import aaa from 'a.vue'
export default {
  //2. 通过 components 注册私有子组件
  components: {
    // 标签名 : 导入的文件
    'my-comcc' :aaa
  }
}
3. 把注册的私有组件名称,以标签形式 引入到自己的UI结构中(把注册的私有组件以标签的形式放到页面上去)
4. 在index.js引入c.vue 注册为全局组件
  import bbb from 'c.vue'
  Vue.component('组件名称': bbb)5.把index.js 中的全局组件名称以标签的形式放到 index.html 中
 
组件之间的数据通信

 父组件向子组件传递数据

创建好父组件和子组件
1. 父组件先要导入 子组件 ,把子组件挂在到父组件的私有组件中
  import 自定义组件名 from '子组件'
2. 在 index.js 导入父组件
  import 自定义组件名 from '父组件'
  注册父组件为全局组件
  Vue.component('组件名': 自定义组件名)
3. 在父组件中的 data 中的数据传给子组件, 子组件中用与data平级 的props:['父组件穿过来的值'] 接收
    props 表示 父组件传递到子组件的数据(只负责接收值)
4. 接收的的值可以直接用 {{父组件传过来的值}} 显示在子组件中
  注意: 父组件向子组件传值 用的是属性绑定,父组件绑定的属性名称是什么,那么子组件必须严格按照父组件规定名称来接收
 
子组件接收的的数据,也可以用 this 来接收;(上图接收到的值 可以直接用 this.msg 转存)
不要轻易修改接收到的父组件穿过来的值 要保证 props中 接收到数据的原装性;
要想修改的话 把接收到的值转存到 data 中,然后直接修改 data中的数据;

注意: 默认情况下,父组件中的数据是私有的,子组件无法直接访问
   父组件传递过来的数据,必须先要使用props 定义和接收之后,子组件才能使用

如果接收的是对象 会有迭代 用 lodash 可以解决
  安装: npm i lodash -S 安装包
  导入到需要用到的lodash的地方
  improt _ from 'lodash'
  用法: 文档 https://lodash.com/docs/4.17.11
  _.cloneDeep(obgects) // 深拷贝
步骤说明: 
① 父组件通过 属性绑定的方法,  把需要传递的值绑定到 子组件上
<son :msg="fMsg"></son>
② 子组件通过 props 来接收 就可以了
props: ['fMsg']
 
 
 
 
props数据验证
 props除了数组之外, 我们也可以使用对象, 当需要props进行类型等验证时, 就需要对象的写法了
验证支持的数据类型有: String、Number、Boolean、Array、Object、Date、Function、Symbol
 props: {
    // 类型限制
    num: Number, // 传递过来的值是数字
    str: String, // 传递过来的值是字符串
    fun: Function // 传递过来的值是 function(方法)
    ............
  },

type: 声明这个参数可以接收的数据类型
default 表示父组件未传入参数时,变量的默认值
required: 声明这个参数是否必须传入
validator:  当校验规则很复杂,默认提供的校验规则无法满足的时候可以使用自定义函数来校验。
 
  // 接收父组件穿过来的值
  props: {
    // fooA只接受数值类型的参数
    fooA: Number,
    // fooB可以接受字符串和数值类型的参数
    fooB: [String, Number],
    // fooC可以接受字符串类型的参数,并且这个参数必须传入
    fooC: {
      type: String,
      required: true
    },
    // fooD接受数值类型的参数,如果不传入的话默认就是100
    fooD: {
      type: Number,
      default: 100
    },
    // fooE接受对象类型的参数
    fooE: {
      type: Object,
      // 当为对象类型设置默认值时必须使用函数返回
      default: function () {
        return { message: 'Hello, world' }
      }
    },
    // fooF使用一个自定义的验证器
    fooF: {
      validator: function (value) {
        return value >= 0 && value <= 100;
      }
    }
  }
props中的驼峰标识
父组件向子组件传递值的时候最好不要使用驼峰标识 那样会报错 最好使用 myName => my-name
子组件接收的时候可以使用驼峰标识()
 
 
父组件向子组件传递普通数据
在父组件中,以标签形式使用子组件的时候,可以通过属性绑定,为子组件传递数据
<my-son :pmsg1="parentMsg" :pinfo="parentInfo"></my-son>
在子组件中,如果向用父组件传递过来的数据,必须先定义 props 数组来接收:  props是与data 、el 平级的,是用来接收父组件传递过来的数据的
<script>
  export default {
    data(){
return {} },
    methods: {},
    
// property 属性
    // 注意:父组件传递到子组件中的数据,必须经过 props 的接收,才能使用;
    // 通过 props 接收的数据,直接可以在页面上使用;注意:不接受,不能使用外界传递过来的数据
    props: ['pmsg1', 'pinfo'] }
</script>
 
接收完的props数据,可以直接在子组件的 template 区域中使用:
<template> <div> <h3>这是子组件 --- {{pmsg1}} --- {{pinfo}}</h3> </div> </template>
 
注意:默认情况下 符组件中的数据 是私有的,字组件无法直接访问 ;要在子组件里添加一个 props 一数组的形式 接收父组件的数据
props 表示 父组件传递到子组件中的数据
注意: 父组件传递过来的数据,必须使用props定义和接收之后,子组件才能使用
父组件通过属性绑定,可以为子组件传递数据, 父组件绑定的属性名称是什么,那么 子组件必须严格按照父组件规定的名称来接收数据
props接收到的数据,可以直接在页面上使用
vue中的props接收到的数据,都是只读的, 今后 如果想要修改props中的数据,必须在data上线转存一份数据,然后直接操作data中转存的数据
 

7.2 父组件向子组件传递方法

如果父向子传递方法,需要使用 事件绑定机制:
<my-son @func1="show"></my-son> // @func1  属于自己定义的
其中,为 子组件传递的 方法名称为 func1, 具体的方法引用,为 父组件中的 show 方法
子组件中,可以直接通过 this.$emit() 方法 来触发父组件为子组件绑定的事件;
this.$emit('事件名称',要传递的数据)
在触发事件的同时 还可以通过第二个参数,传参回父组件中
 
想要深拷贝 要使用到 lodash 安装方法:
  1. npm i lodash -S     
2. 在直接调用就可是使用了 _.cloneDeep()  深拷贝
 

7.3 子组件向父组件传值

   什么时候需要使用自定义事件: 
  ①当子组件需要向父组件传递数据时, 就要用到自定义事件
  ②v-on不仅可以用于监听DOM事件, 也可以监听自定义组件之间的自定事件
 自定义事件的流程:
  ①在子组件中通过$emit() 来触发事件
  ②在父组件通过 v-on 来监听子组件事件
  子向父传值,要使用 事件绑定机制@;
       父向子传递一个方法的引用
      子组件中,可以使用 this.$emit() 来调用父组件传递过来的方法
      在使用this.$emit()调用 父组件中方法的时候,可以从第二个位置开始传递参数;把子组件中的数据,通过实参,传递到父组件的方法作用域中;
      父组件就可以通过形参,接收子组件传递过来的数据;
  this.$emit('要传递的事件名称','要传递的参数')
 
 

7.4 兄弟组件之间传值

 
发数据的一方用 JS文件夹名.$emit( '事件名称', 要发送的数据) 发送数据  接收的一方用 JS文件夹名.$on('事件名称' , function(){ 接收的数据 }) 接收数据
注意:兄弟组件之间,实现传值,用到的技术,是 EventBus
 
创建一个公共的js文件夹  这个js文件夹本质上就是一个vue实例对象
import Vue from 'vue' // 导入 Vue
export default new Vue() // 把vue 暴露出去
俩个兄弟文件同时导入公共的js文件夹
import 自定义名称 from '公共文件'
在数据发送方,调用 自定义名称.$emit('事件名称' , '数据')  触发某个事件 从而发送数据
export default {
  data () {
    return { GGMsg: '这是GG的数据' }
  },
  methods: {
    sendMsgToDD () {
      bus.$emit('ooo')
    }
  }
}

在数据接收方,通过 自定义名称.$on()方法,自定义一个事件,只要有人触发了这个自定义事件,必然会调用指定的处理函数

在需要接收数据的兄弟组件中的 created 生命周期函数里,
使用 自定义名称.$on('事件名称', 处理函数(接收的数据) => {}) 自定义事件:
created() { // 通过 bus 的 $on 方法,可以为实例对象,绑定 自定义事件;
  bus.$on('ooo', data => {
    // 把接收到的数据 绑定到自己的 data 上 
    this.msgFromGG = data
  })
}
 Vue实例对象上有两个方法.$emit 和.$on 这两个是配合使用的
  Vue实例.$emit 是用来触发事件的   Vue实例.$emit('要被触发的事件', 要传递的数据)
  Vue实例.$on 是用来注册事件的   Vue实例.$on('触发的事件名称', (data) => { })   // data是 事件触发者传递过来的数据 
 
 
 

使用 this.$refs 来获取元素和组件

把要获取的DOM元素,添加 ref 属性,创建一个DOM对象的引用,指定的值,就是引用的名称:
// 子组件标签
<cpn
ref="myElement11">大家好</cpn>
如果要获取 某个引用所对应的 DOM对象,则直接使用 this.$refs.引用名称
默认情况下this.$refs 是空对象
 methods: {
        btnClick() {
          console.log(document.getElementById('myh1').innerHTML) // 结果是 大家好
          console.log(this.$refs.myElement11.innerHTML) // 结果是 大家好
        }
      },
也可以使用 ref 为组件添加引用;可以使用 this.$refs.组件应用名称, 拿到组件的引用,从而调用组件上的方法 和 获取组件data上的 数据;
只要通过 ref 拿到了 组件的引用对象 就可以直接通过 组件的引用对象, 调用组件 methods中的方法,或修改组件data中的数据
<h1 id="myh1" ref="mytest2">hello,大家好,我是咕天乐</h1>
const dom = document.getElementById('myh1')
console.log(this.$refs.mytest2 === dom)  // 结果是 true
 
使用 this.$parent查找当前组件的父组件。
使用 this.$children查找当前组件的直接子组件,可以遍历全部子组件, 需要注意 $children 并不保证顺序,也不是响应式的。
使用 this.$root查找根组件,并可以配合$children遍历全部组件。
使用 this.$refs查找命名子组件。
 
父组件访问子组件: 使用this.$children或者this.$refs
  直接使用this.$children children是一个复数 访问的不止一个, 所以他返回的是一个数组 组件集合
  使用$refs
    给子组件添加ref属性
<cpn ref="cpnClick"></cpn>
子组件访问父组件: 使用this.$parent
// 直接在子组件中直接打印
console.log(this.$parent)
 访问根组件 $root
    cpnClick() {
              console.log(this.$root);
            }
 

使用 霸道的 render 函数渲染组件

如果在 vm 实例中既指定了 el 又指定了 render 函数,则会把 el 所指的的区域,替换为 render 函数中所提供的组件;

既然 render 函数会替换到 el 区域内的所有代码,也会让 template 属性失效;因此,在删减版的 vue 包中,new 出来的 Vue 实例对象,不允许 挂载 data 属性和 template 属性!
 
当时用 render 渲染指定组件的时候,VM实例对象中的data 和 template 都没有任何意义了
// render 是和el,data 平级的函数 可以把指定的页面,渲染到index.html 中 
render:function(createElement){ // createElement 形参是一个方法,作用是: 把指定组件,渲染出来,并替换 el/template 所指区域 
  return createElement(要渲染的组件) 
}
也可以这样写:
render: createElement=>createElement(要渲染的组件)

// 普通用法 createElement('标签',{标签属性},[标签中的内容])

 

 
SPA(Single Page Application)单页应用
锚链接及常规的url 的区别
  1. 普通的URL地址,会刷新整个页面,会追加浏览器的历史记录
  2. 锚链接 不会触发页面的整体刷新,会追加浏览器的历史记录(锚链接是在页面内的跳转)
 
SPA概念定义: SPA英文全称是 single page application  中文翻译是”单页面应用程序”
通俗的理解是:  zhiyou yige WEB 页面的网站。网站的所有功能都在这个唯一的页面上进展与切换
 
Spa的特点:
  1. 整个网站只有一个页面
  2. 浏览器以开始请求这个页面,必须加载对应的HTML CSS JavaScript
  3. 用户的所有操作,都在这唯一的页面上完成
  4. 页面数据都是用ajax 请求回来的
Spa好处:
实现了前后端分离开发,各司其职。提高了开发效率
用户体验好、快,内容的改变不需要重新加载整个页面
Spa的缺点:
SEO(搜索引擎优化)不是很友好,因为页面数据是ajax渲染出来的
刚开始的时候加载速度可能比较慢,
页面复杂度比较高,对程序员能力要求较高
 
使用<component>标签实现组件切换

component 是有vue官方提供的,作用 就是根据 is属性指定的名称,来展示指定的组件

1. 把需要展示的组件导入
2. 注册为私有组件
3. 在data中创建一个属性, 把需要默认展示首页的组件标签名称填入
<component>是vue提供的,作用是 把 :is 指定的组件名称 渲染到 <component> 内部
身上有一个 :is 属性
可以把component 标签理解为占位符 值是什么名称 就会展示什么名称组件
单页面应用程序中,实现组件切换的根本技术就是监听window.onhashchange事件(在created使用)
// 可以拿到地址栏中 #后边的hash值 (可以在后台 自己拿一下看看)
// 用这个的时候 推荐使用 switch
// 这是原生的方法
  window.location.hash //http://www.w3school.com.cn/js/js_window_location.asp
 
 
 
 
路由
路由就是对应关系
  1. 后端路由的定义:URL地址到后端处理函数之间的关系
  2. 前端路由的定义:hash到组件之间的对应关系
  3. 前端路由的目的:为了实现单页面应用程序的开发
  4. 前端路由的组成: ① 链接 ②组件 ③链接与组件之间的对应关系
 
vue中使用vue-router
安装导入并注册路由模块
 运行 npm i vue-router -S 安装路由模块
 index.js中导入并注册路由模块
// 导入路由模块
import VueRouter from 'vue-router' 
// 注册路由模块(把路由安装到 Vue 上) 
Vue.use(VueRouter)
 
创建路由链接 
<!-- router-link 就是 第一步,创建 路由的 hash 链接的 -->
<!-- to 属性,表示 点击此链接,要跳转到哪个 hash 地址, 注意:to 属性中,大家不需要以 # 开头 -->
<router-link to="/home" tag="li">首页</router-link>
<router-link to="/movie">电影</router-link>
<router-link to="/about">关于</router-link>
tag 属性 要渲染成什么标签 默认 是 a标签 tag可以转换成自己想要的标签
创建并在index.js 中导入路由相关的组件 
import Home from './components/Home.vue' 
import Movie from './components/Movie.vue' 
import About from './components/About.vue'
创建路由规则 
    // 创建路由对象 前端路由: hash 值 到组件的对应关系 一个hash 对应一个要展示的组件 
    // 创建路由规则(对应关系)
    // 配置对象中要提供hash 地址到组件之间的 对应关系
    const router = new VueRouter({
      // routes 是路由规则数组,其中的每个对象 都是一天路由规则 
      routes: [
        // 这个 routes 就是 路由 规则 的数组,里面要放很多的对应关系
        //路由规则的基本组成 { path: 'hash地址', component: 配置对象(要展示的组件) },在path中 ,带冒号的,是路由参数项
           // 通过 redirect是属性,可以实现前端路由的重定向 
           { path: '/', redirect: '/home' },
        // 如果访问的是 根路径 就会跳转到指定路径 
        { path: '/home', component: Home },
        { path: '/movie', component: Movie },
        {
          path: '/about', component: About,
          children: [ // 子路由
        {
  path: '/',   component: ''
        } ] }] }) // 创建的 router 对象,千万要记得,挂载到 vm 实例上 const vm = new Vue({ el: '#app',
    render: c => c(App),
    router: router
// 把 创建好的路由对象,一定要挂载到 VM 实例上,否则路由不会生效 })
在页面上放路由内容 
<!-- 这是路由的容器,将来,通过路由规则,匹配到的组件,都会被展示到这个 容器中 --> <router-view/>
使用

// 在 app.vue中使用 router-link

 

// <router-link> 标签 将来会被 默认 渲染为 a 链接 
// to 属性 表示 点击这个链接 要跳转到哪个 hash 值 to 相当于 href
// 展示的地址要和 path 对应上 <router-link to="/地址"></router-link>
// router-view 这是一个占位符 将来通过 路由规则 匹配到的组件 会被替换到router-view所在的位置 <router-view/>
  
路由规则的匹配过程
1. 用户点击 页面的 路由链接router-link,点击的一瞬间,就会修改 浏览器 地址栏 中的 hash 地址;   
  router-link标签,将来会被默认渲染为 a 链接   
  to属性 表示点击这个链接要跳转到哪个hash值   redirect 重定向
2.当 hash 地址被修改以后,会立即被 vue-router 监听到,然后进行 路由规则的 匹配;最终,找到 要显示的组件
3. 当 路由规则匹配成功以后,就找到了 要显示的 组件,然后 把 这个组件,替换到 页面 指定的 路由容器router-view 中
4. router-view这是一个占位符,将通过路由规则 匹配到组件,会被替换到 router-view 所在的位置 只要是路由组件必须要有占位符
 
 
设置路由高亮的两种方式
  1. router-link 有一个 router-link-active 类名
  2. 通过路由默认提供的 router-link-active 类名,为这个类添加自己的高亮样式即可
  3. 通过路由构造函数,在传递路由配置对象的时候,提供linkActiveClass属性,来覆盖原有的高亮样式
  与routers平级中有一个linkActiveClass , 这个的意思是: 被激活的路由类名,默认是router-link-active,想要修改只要在这个里面输入 要被修改成什么 就可以( 简单来说就是: 这个对象是 指定代码高亮的样式的 )
 
嵌套路由(子路由)
  1. 在对应的路由组件中,新增 router-link 路由链接
  2. 创建 router-link 对应要显示的组件
  3. children属性 是数组,表示子路由 是routes第三个参数
  4. 在对应的路由规则中,通过 children属性,定影子路由规则
 
{ 
  // redirect 重定向 
  path: '/movie',
  component: Movie,
  redirect: '/movie/in_theaters',
   // 指定子路由规则 
  children: [ 
    { path: '/movie/in_theaters', component: In_theaters }, 
    { path: '/movie/coming_soon', component: Coming_soon } 
    ] }
在router-link之下 添加router-view容器组件
可以使用redirect 实现 嵌套路由的重定向
router-link 的to 属性,可以使用v-bind属性绑定 动态绑定一个路由地址
     tag 属性 要渲染成什么标签 默认 是 a标签
router-link 默认渲染为 a 链接,可以使用 tag 属性 强制router-link渲染为特定的标签(如: li <router-link tag="li" to="">)
 

路由传参

开启路由传参:
如果在组件在,想要拿到 path 中匹配的路由参数项,可以为 路由规则 开启 props传参
// 开启路由传参 添加 props, props与path平级
{ path: 'login/:id', component: login, props:true }
路由传参,首先,要把路由规则中,对应的参数位置,通过: 来定义为一个参数;
可以在组件中,直接使用this.$route.params.id 来获取参数;【写起来太麻烦,不推荐】
也可以开启路由的 props 传参,来接收路由中的参数;【推荐方式】
如果在组件中,想要拿到path 中匹配的路由参数项 可以为路由规则开启 props传参 (props:true)
在需要传参的路由规则中,添加 props: true 如下 :
// 在路由规则中,可以把参数项的前面添加 : 
// :id 表示要传入的参数 记得有 冒号 属性绑定
// 在 对应的组件中,定义 props 并接收路由参数
{ path: '/movie/:type/:id', component: movie, props: true }
const movie = { // 使用参数 template: '<h3>电影组件 --- {{type}} --- {{id}}</h3>', props: ['type', 'id'] // 接收参数 }

// 在需要使用的地方添加[不常用]
// 在页面直接打印 {{id}} 可以查看传递过来的参数
export default {
  props: [ 'id' ] // 接收的参数
}
// 在新页面 用 $route.params.参数名 也可以接收到传递的参数
// 在页面 使用 {{$route.params.参数名}} 可以查看传递过来的参数值
.vue文件中,只要使用v-for 指令,必须要有 :key 属性

3.7 命名路由

命名路由是 就是为路由规则,添加了一个 name ;
什么是命名路由
router-link中通过路由名称实现跳转
命名路由使用 params属性传参
routes: [{ 
  path: '/login',
  component: login,
  name: moviePage
  }] 
// 通过命名路由,实现路由跳转
// name 是命名路由的名称对象
// 给他绑定一个对象 name 要去那个路由里边 params 传递的参数
<router-link :to="{ name: 'moviePage', params: {type: 'top250', id: item.id} }" tag="li" v-for="item in list" :key="item.id">
</router-link>
// 这是使用字符串拼接,得到的 路由地址 实现跳转
<router-link :to="'地址'+item.id" tag="li" v-for="item in list" :key="item.id"></router-link>
 
 

3.8 编程式(JS)导航  // https://router.vuejs.org/zh/guide/essentials/navigation.html

之前的router-link是标签跳转;除了使用router-link是标签跳转之外,还可以使用Javascript来实现路由的跳转;
编程式导航
使用vue-router提供的JS  API实现路由跳转的方式,叫做编程式导航;
编程式导航的用法 
// 如果要跳转指定的 hash地址, 只能使用push方法
this.$router.push('路径的地址') 如果要跳转到指定hash地址,只能使用push方法
this.$router.go(n)   n == -1 后退一步  n==1 前进一步
this.$router.forward() 前进一步
this.$router.back()  后退一步
以上的记得都要注册在methods 里 的方法里
methods: { 
// 在调用这个 写在行内的不行
goBack() { this.$router.go(-1) }
 }
 
 
this.$route 是 路由参数对象
this.$router 是路由导航对象
vm 实例上的 router 属性,是来挂载路由对象的
new VueRouter({ /* 配置对象 */ }) 的时候,配置对象中,有一个 routes 属性, 是来创建路由规则的

 

3.9 路由导航守卫

案例需求:只允许登录的情况下访问 后台首页 ,如果不登录,默认跳转回登录页面;
API语法:
// router.beforeEach(to, from, next)方法,会在每个路由规则被匹配之前 做一件事
// to :是要去的那个页面 路由相关的参数 (表示 将要访问的那个路由对象)
// from :从哪个页面即将离开 (从哪个路由对象,跳转而来)
// next :next 是一个函数,就相当于 Node 里面 express 中的 next 函数 (代表放行)
       // next() 表示放行 next('/login') 表示强制跳转到login页
// 注意: 这里的 router 就是 new VueRouter 得到的 路由对象
router.beforeEach((to, from, next) => { /* 导航守卫 处理逻辑 */ })​

window.sessionStorage.getItem('token') // 获取 token字符串
window.sessionStorage.clear() // 清空当前所有缓存 https://developer.mozilla.org/zh-CN/docs/Web/API/Window/sessionStorage
 
// 引入路由导航 import Router from 'vue-router'
import login from '路由地址/login'
import home from '路由地址/home'
// 创建路由
const router = new Router({
  routes: [
    {path: '/login', component: login},
    {path: '/home', component: home}
  ]
})
// 创建路由拦截器 // to 表示 去那个路由
// from 表示 从哪个路由而来
// next 表示 放行
router.beforeEach((to,from,next)={
// 判断语句
  // 如果是去login, 直接放行
  if(to.path === '/login') return next()
  // 如果去 home 要先判断是否有token字符串
  const tokenStr = window.sessionStorage.getItem('token')
  // 如果没有token 强制跳转到 login页面
  if(!tokenStr) return next('/login')
  // 有token直接放行
  next()
})
// 把路由对象暴露出去
export default router
 
 

4. watch 监听数据

watch 监听的特点:监听到某个数据的变化后,侧重于做某件事情;
  缺点: 只能监听一个数据的变化;
  watch是与el data平级的
只要被监听的数据发生了变化,会自动触发 watch 中指定的处理函数;
watch:{
    password:function(newVal,oloVal,){
        console.log(newVal) // 输入的新值 
        console.log(oloVal) // 老值 
    }
}​
 

5. computed 计算属性

计算属性特点:同时监听多个数据的变化后,侧重于得到一个新的值;
只要依赖的任何一个数据发生了变化,都会自动触发计算属性的重新求值;
计算属性,在定义的时候,需要被定义为function ,但是在页面UI结构中,计算属性是直接当做 普通属性来使用的 在计算属性中 必须return 一个返回值
 
 在 Vue 中,computed 的属性可以被视为是 data 一样,可以读取和设值,因此在 computed 中可以分成 getter(读取) 和 setter(设值),
一般情况下是没有 setter 的,computed 预设只有 getter ,也就是只能读取,不能改变设值
 
 
computed 和 methods 的区别?
1、相同点
如果作为模板的数据显示,二者能实现响应的功能,唯一不同的是methods定义的方法需要执行
2、不同点
computed 会基于响应数据缓存,methods不会缓存
diff之前先看data里的数据是否发生变化,如果没有变化computed的方法不会执行,但methods里的方法会执行
 
 
使用vue-cli 快速创建vue项目
首先安装 npm  i vue-cli -g  // 安装全局的vue 脚手工具
vue init webpack 项目名称 // 初始化项目
npm i  // 安装 vue所需要的包
npm run dev (npm run serve)// 运行终端(运行项目)
npm run build// 打包
npm run build --report // 查看打包后的视图
 
自定义指令
全局自定义指令
概念:在全局任何组件中东可以被调用的自定义指令,就是全局自定义指令
语法:Vue.directive(‘全局自定义名称’,{/* 自定义指令配置对象 */})
自定义指令的名称,在定义的时候不需要加 v- 前缀,但是在使用的时候 必须加上 v- 前缀
Vue.directive('red',{ 
    // 当指定被第一解析的时候,就会触发bind方法 
    // 此时 指令所绑定到的元素 还没有被插入父节点中
    // 【推荐】在bind方法中,为指令所绑定到的元素设置样式相关的属性
     bind:function(el, binding){
        // el 指的是DOM元素
         // binding 是指令所绑定的一些数据,其中,binding.value就是指令 =(等号) 后面的数据
           el.style.color = 'red';
          el.style.color=binding.value
           }
          })
 

  
私有自定义指令
概念:只有指令所属的组件中,才可以被正常调用的指令,是私有自定义指令
语法:
// test1.vue 组件
<template></template>
 
<script>
    export default {
        directives: {
           //  '私有自定义指令名称': { /* 私有自定义指令配置对象 */ }
    bind: function(el) {
      el.style.background = 'red'
    }
        }
    }
</script>


指令配置对象中的
bind 和 inserted 的区别

bind 方法:
  1. 绑定当前指令的元素,在内存中被创建的时候就会被立即调用
  2. 推荐吧样式相关的设置,都定义在bind 方法中
Inserted方法:
  1. 绑定当前指令的元素,被插入到DOM树之后才会被调用
  2. 推荐把行为 相关的设置,都定义在inserted 方法中
想要查看bind和inserted 的区别 终端中打印 el.parentNode 即可
总结:在bind 中队员说的样式进行操作 ,在inserted 中 对元素的行为进行操作
 
插槽 slot
组件插槽是为了让我们封装的组件更加酷游扩展性
让使用者可以决定内部的一些内容到底展示什么
定义:定义子组件的时候,在子组件内部刨了一个坑,父组件想办法王铿里天内容
 
单个插槽(匿名插槽)
定义插槽:在子组件作用域中,使用 <slot></slot> 定义一个插槽;
使用插槽:在父作用域中使用带有插槽的组件时,组件内容区域中的内容,会插入到插槽中显示;
     如果在定义某个组件的时候,不太确定组件中的某一部分,具体显示什么UI元素,此时 可以把这个区域定义为一个占位符(插槽),今后,这个占位符中具体显示什么标签,是有使用者决定
谁使用这个组件,谁就可以为这个组件指定插槽中要渲染的UI结构,这个指定的UI元素,会被替换到<slot></slot>插槽的位置
使用的方法 :
  ①在组件中定义一个 <slot> 标签  
①基本使用
 直接定义一个 <slot>标签
② 默认值
在<slot>标签中写入默认的值
<slot><span>内容</span></slot>
注意: 如果在调用的slot标签中输入内容 会把默认值替换掉
  ②在标签中定义要展示的信息
// html部分
    <slot><button>按钮</button></slot>
    <slot><i>内容</i></slot>
    <slot><button>按钮</button></slot>


// 子组件部分
<template id="cpn">
  <div>
    <h6>我是子组件</h6>
    <slot></slot>
  </div>
</template>

显示结果

如果, 相同部分多次调用 可以在 slot 中直接写入当做默认值来使用
// HTML部分
<cpn></cpn>
<cpn><span>内容</span></cpn>
<cpn></cpn>
// 子组件部分
<template id="cpn">
  <div>
    <h6>我是子组件</h6>
    <slot></slot>
  </div>
</template>
显示的结果与上面的结果是一样的 
slot标签中如果有内容的话 会当做默认值使用
 
 
注意: 在一个组件中,只允许出现一个 匿名插槽
 
多个插槽(具有名字的插槽)
具名插槽的调用: 
  ①首先要把定义好的组件导入到需要使用的地方
import head from './slot/head'
  ②在把导入的组件定义到 components 中
components: {top: head}
  ③把定义好的名称 在页面中当做标签使用
    <top></top>
 
定义具名插槽:使用 name 属性为 slot 插槽定义具体名称;
<slot name="header"></slot> // header 自己定义的
 
使用具名插槽:在父作用域中使用带有命名插槽的组件时,需要为内容指定 slot="name" 来填充到指定名称的插槽;
<span slot="header"></span>
 
 
作用域插槽(常用)
官方给出的解释是: 父组件模板的所有东西都会在父级作用域中编译;子组件模板的所用东西都会在自己作用域中编译;
父组件替换插槽的标签, 但内容由子组件提供
定义作用域插槽:在子组件中,使用slot定义插槽的时候,可以通过属性传值的形式,为插槽传递数据。
例如:

  <div id="app">
    <cpn>
   <!-- .vue 2.5.x一下必须有template -->
      <template slot-scope="slot">
          {{slot.row.data}} // 拿到的数据是: [ "javascrpit", "typescript", "c++", "c#", "python" ]
      </template>
    </cpn>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <template id="cpn">
    <div>
      <slot :data="language">
        <ul>
          <li v-for="item in language">{{item}}</li>
        </ul>
      </slot>
    </div>
  </template>
  <script>
    var vm = new Vue({
      el: '#app',
      components: {
        cpn: {
          template: '#cpn',
          data() {
            return {
              language: ['javascrpit''typescript''c++''c#''python']
            }
          }
        }
      }
    });
  </script>

使用作用域:在父作用域中,通过定义 slot-scope=”slot”属性,接收并使用插槽数据slot添加属性绑定,把插槽中需要渲染的数据传递给外界使用者
可以在使用组件的时候,通过定义slot-scope属性接收插槽传递出来的数据
注意: template 标签,只会起到包裹元素的作用,不会被渲染成任何标签元素
  在同一组件中 不同插槽的作用域 是独立的
 
 
 
安装和使用 element-ui
element-ui 饿了么 前端团队 开源出来的一套Vue组件库
  1. 完整版引用 element-ui组件
运行 npm i element-ui -S 安装组件库
在main.js中 导入element-ui的包 配置样式表 并且安装到Vue
// 导入 element-ui 这个包
import ElementUI from ‘element-ui’
// 导入 配套的样式表
import ‘element-ui/lib/theme-chalk/index.css’
//在把 element-ui 安装到 Vue 上
Vue.use(ElementUI )
 
    import Vue from 'vue';
    import { Button, Select } from 'element-ui';
    import App from './App.vue';
    /*
    Vue.component(Button.name, Button);
     Vue.component(Select.name,Select); 
     */
    // 或写为 
    Vue.use(Button)
     //按钮样式 Vue.use(Select)
     // 弹出层 new Vue({ el: '#app', render: h => h(App) });
 

 

 

在在
webpack.config.js 文件中的 rules 添加一条配置样式 
{ test:/.eot|ttf|woff|woff2$/,use:'url-loader'}
 
  1. 按需要导入和配置 element-ui
<divclass="p"> 运行 npm i babel-plugin-component -D 安装支持按需要导入的模块 <divclass="p"> babel-plugin-component 会根据你用了几个组件 ,按需要榜我们引入对应的CSS 样式 就不需要自己导入最全的样式了 <divclass="p">打开 .babelrc 配置文件 想改如下
{ "plugins": [
  "transform-runtime",
    [ // +好表示要添加的项
      "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ]
  ],
  "presets": [
  "env",
  "stage-0"
  ]
}
 
 
 
如果希望只引入部分组件 ,那么需要在 main.js中写入 如下内容 
 

ESlint 语法检查规范 ( 会出警告的可能情况 ) 
  1. 声明但是没有使用的变量会报错
  2. 空行不能连续大于等于 2
  3. 在行结尾处,多余的空格不允许
  4. 多余的分号 不允许
  5. 在方法名和形参列表的小括号之间,必须有空格
  6. 在单行注释的 // 之后 必须有一个空格
  7. 字符串要使用单引号 不能使用双引号
  8. 在每一个文件的结尾 都要有一个唯一的 空行   不然会有警告
 
模拟后台数据json-server
运行命令 npm i install json-server -D 全局安装 json-server
项目根目录创建 mock 文件夹
mock文件夹下添加 db.json 文件 自己所需要模拟的数据
{ "posts": [ 
    { "id": 1, "title": "json-server", "author": "typicode" } 
    ],
     "comments": [
     { "id": 1, "body": "some comment", "postId": 1 }
     ],
     "profile": { "name": "typicode" } 
    }
 
package.json 添加命令  打开package.json文件 在scripts节点中 新增一个 mock 的节点
"mock": "json-server --port 3333 --watch mock/db.json"
 
 打开终端 运行 npm run mock 运行 json-server服务器
faker.js 创建假数据
运行 npm i faker -D 安装生成假数据的包
运行 npm o lodash -S 安装 lodash,利用 _.times( ) 方法循环调用 faker生成数据
mock 目录下的 db.josn 改名为 db.js
修改db.js 中的代码
// 导入 lodash 
    const _ = require('lodash')
    // 导入 faker 生成假数据
    const faker = require('faker')
    // 设置数据本地化 (把随机生成name改成中文)
    faker.locale = 'zh_CN'
    // 使用 CommonJS 规范把生成的数据导出;
    // 其中,module.exports 必须指向 函数,且函数中,必须 return 一个数据对象
    module.exports = () => { // json-server 要求最终 return 的数据,必须是一个对象;
      const data = { brandlist: [] }
      // 调用 _.times 随机 10 次生成假数据 
      data.brandlist = _.times(10, n => {
        return {
          id: n + 1,
          //使用索引你模拟Id 
          name: faker.random.word(), ctime: faker.date.recent()
        }
      })
      // 把生成的数据返回
      return data
    }
 
 
 

  
$nextTick() 方法的作用,就是当页面上的元素重新渲染之后,才会执行的 回调函数中的代码
 
使用Gzip 的好处:
如果服务器,启用Gzip,则文件在网络中 传输的时候,会被压缩;经过Gzip的压缩之后,文件的体积
 
CDN 就是 网速特别快的 一台服务器 (网址: https//www.bootcdn.cn)
 


  

<!--子组件内容 -->
created() { // 通过 bus 的 $on 方法,可以为实例对象,绑定 自定义事件;
  bus.$on('ooo', data => {
    // 把接收到的数据 绑定到自己的 data 上 
    this.msgFromGG = data
  })
}
 
build文件夹下的文件
vue-loader.conf.js     
webpack.base.conf.js  基本配置文件  不管是开发还是 项目上线都会用到
webpack.dev.conf.js    开发环境下的配置文件
webpack.prod.conf.js   上线(发布)环境下的配置文件
 
 
 
把项目中一些比较大的包,抽离为外部加载的方式
// 在build文件夹下的 webpack.prod.conf.js 文件中的 添加externals 
// externals与module 平级
externals: {
  // 包名: '构造函数'  
  // 在这里导入后 记得要在 index.html 导入vue  包的地址可以去 www.bootcdn.cn网站上搜索
  vue: 'Vue',
 'vue-router': 'VueRouter' }
https://www.bootcdn.cn/ CDN镜像加速(就是网速特别快的一台服务器)
原文地址:https://www.cnblogs.com/maxiag/p/10409170.html