学习Vue这一个就够

1、淘宝镜像
 1: 解释一下 npm 为什么要配置淘宝镜像
      原因:因为node.js 默认使用的是国外的网站 。国内访问有一个跨国内局域网的操作。所以就会有时候很慢。这就跟为什么网站的静态资源有些会使用CDN 加速一样的
     淘宝镜像是什么?就是npm 很多的插件淘宝已经下载好了放在公共的网站上 我们需要的时候去淘宝网上下载 和 国外的是一样  这样使用是提升了我们的下载速度。所以淘宝镜像其实是一个国外插件的 国内版本
 2:安装命令
     npm config set registry https://registry.npm.taobao.org
 3:查看是否安装成功 
    npm info express
 4:使用命令 
    npm install -g cnpm --registry=https://registry.npm.taobao.org
     cnpm install <插件名>
3、安装vue的调试工具
1、插件已经下载好,直接拖着往谷歌浏览器的扩展程序里面,记得是开发者模式(教学案例)

1、理解什么是Vue

0:官网https://cn.vuejs.org/guide/introduction.html
  https://cdn.jsdelivr.net/npm/vue@2  压缩版
  https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js  生产版
1、Vue.js是目前最火的框架,是前端的主流框架之一,和Angular。js和React.js
并称为三大主流框架
2、Vue.js是一套构建用户界面的框架,只关注图层,不仅易于上手,HIA方便与第三方库或既有项目整合(有配套的第三方类库,可以整合起来做大型项目的开发
3、使用vue往html页面中填充数据,非常的方便。框架都是现成的解决方案,按照框架的规范,去便携自己的业务功能
4、主要就是学习vue的指令、组件、路由、vuex
5、vue的特性:
   1、数据驱动视图
   2、双向数据绑定

2、如何学习Vue

1、能够使用Vue的指令完成页面结构的渲染
2、能够使用Vue的调试工具辅助Vue的开发
3、了解什么是过滤器和侦听器,能够在实际开发中解决问题
4、什么是计算属性以及计算属性的用法
5、axios的基本用法,使用axios发起ajax请求
6、vue-cli,脚手架的安装和使用,生成工程化的Vue项目
7、组件的注册与使用,掌握vue单文件组件的基本用法
8、组件的props自定义属性
9、解决组件样式冲突
10、学习组件的生命周期,掌握组件声明周期的执行顺序和应用场景
11、组件之间的通讯(数据共享),组件之间通讯的三种方式
12、学习ref应用DOM元素和组件实例,能够使用ref获取页面上的DOM、或组件的引用
13、$nxtTick的基本使用,能够知道$nxtTick的应用场景并合理的使用
14、学习动态组件的使用,能够使用keep-alive实现组件的缓存
15、自定义指令
16、学习ESLint的使用,能够了解ESLint的语法规则
17、学习使用(默认插槽、具名插槽、作用域插槽),能够使用插槽提高组件的复用性
18、学习路由的基本配置与使用,能够在项目中安装和配置路由
19、路由重定向
20、嵌套路由、动态路由
21、编程式导航、路由导航守卫,能够使用路由实现单页面程序的开发。使用导航收尾控制路由的访问权限
22、学习Vant,掌握Vant组件库的基本使用,知道如何封装axios请求模块

3、数据驱动视图

1、在vue的页面中,vue会监听数据的变化,从而自动重新渲染页面的结构
  页面结构<-vue(监听数据的变化,数据发生改变)<-页面发生变化
  好处:当页面数据发生变化时,页面会自动重新渲染,只需要管理好数据
  注意:数据驱动视图是单向的数据绑定
  总结:数据的变化会驱动视图自动更新,
3-1、数据代理
1、数据代理:通过一个对象代理另一个对象中属性的操作

2、vue中采用数据代理Object.defineProperty中的setter和getter进行数据代理和数据的响应
3-2、VueComponent
1、整个项目只会有一个Vue实例对象vm,其他的都是VueComponent实例对象,

2、VueComponent的实例对象,简称为vc,也称为组件实例对象,Vue的实例对象只有一个,称为vm

3、VueComponent可以通过Vue.extend()方法创建个很多个vc。在项目里面的组件实例对象就是通过这种方式创建的。就是vc

4、vm和vc很多东西都一样,但是vc可以有很多个,vm只能有一个,而且vm可以设置el指定渲染的容器,vc不行。

4、双向数据绑定

1、填写表单的时候,双向绑定可以在不操作DOM的前提下,自动把用户填写的内容同步到数据中。
    页面结构<->vue(监听数据的变化,数据发生改变)<->页面发生变化
    form表单负责采集数据,ajax负责提交数据
    用户不需要手动操作dom元素,来获取表单数据
    页面上表单采集的数据发生变化的时候,会被vue自动获取到,并更新到js数据中。

4-MVVM核心原理(数据驱动和双向绑定的原理)

1、MVVM是vue实现数据驱动视图和双向数据绑定的核心原理。MVVM指的   是Model、View、ViewModel,把每个页面都拆分成了这三个部分。
   Model表示当前页面渲染时所以来的数据源
   View表示当前页面所渲染的DOM解构
   ViewModel表示Vue的实例,是MVVM的核心。就是vue
2、ViewModel作为MVVM的核心,是把当前页面的数据源和页面的结构连接在了一起。

view 《--(自动更新,监听DOM变化)--》ViewMOdel《---(监听数据变化,自动同步)--》Model
  
  当数据源发生变化是,会被ViewModel监听到,VM会根据最新的数据源自动更新页面的结构。
  当表单的值发生变化时,也会被VM监听到,VM会把变化过的最新的值自动同del数据源中

学习Vue这一个就够_第1张图片

5、Vue的版本

1.0版本基本被淘汰,
2.x版本是目前企业级项目开发中的主流版本
3.x的与2020年-09发布,现在已经是默认版本了,但是还没有普遍使用
vue的作者:尤雨溪,是中国人开发的前端框架
react和angular都是外国人开发
比较简单

6、Vue的基本使用

1、导入vue.js的script脚本文件
2、在页面中声明一个将要被vue所控制的DOM区域
3、创建一个vue实例
4、实例里面选择渲染的区域,定义要渲染的数据变量,
   <!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 1、引入vue的js文件,有vue这个构造函数 -->
    <script src="../lib/vue.js"></script>
</head>

<body>
    <!-- div控制页面,需要被vue控制 -->
    <!-- 数据渲染:插值语法,可以把数据渲染到页面 -->
    <div id="app">{{username}}</div>
    <script>

        // 2、创建一个vue实例对象
        const vm = new Vue({
            // 3、el属性是固定的写法,表示vm实例要控制页面上的
            // 哪一个区域,接收的值是一个选择器
            el:'#app',
            // data是数据,所有用到的边浪在data里面定义
            // 然后渲染到页面上去
            // 这里是对象形式
            data:{
                username:'xiaohong'
            }

        })
    </script>


</body>

</html>
el指向的选择器选择的div就是view视图区域,data指向的对象就是MOdel数据源,new Vue是构造函数,创造了一个vm实例对象,就是viewModel。

7、配置Chrome浏览器的vue-devtools

1、插件已经下载好。可以直接使用

8、Vue的指令和过滤器

1、指令是VUe为开发者提供的模板语法,辅助开发者渲染页面的基本结构
2、指令按照不同的用途,分为六大类
   1、内容渲染指令
   2、属性绑定指令
   3、事件绑定指令
   4、双向绑定指令
   5、条件渲染指令
   6、列表渲染指令
8-1、内容渲染指令
1、内容渲染指令用来辅助开发者渲染DOM元素的文本内容,常用的内容渲染指令有3个
   1、v-text:会覆盖元素内部原有的内容,实际开发用的不多
   2、{{}}:插值表达式,不会覆盖默认文本,解决v-text的问题,可以在括号里面加点空格,内容占位符,只能用在内容节点,不能用在元素的属性节点。还
   3、v-html:其他两种只能渲染纯文本内容,该指令能把包含html标签的字符串渲染为页面的html元素,
2、总结:v-html渲染html标签,v-text和{{}}渲染纯文本,但是v-text会覆盖原本的内容,用的最多的是{{}}
      
        
        
{{username}}你好
你好
你好
8-2、属性绑定指令(v-bind)
1、插值表达式只能用在内容节点中,不能用在元素节点中
2、v-bind:  给元素的属性动态绑定属性值,可以省略v-bind,保留 :
    
      
      

      

      
      
3、注意:如果要用v-bind进行字符拼接,记得给字符串加上''
4、v-bind里面是js语句,
使用javascript表达式
1、在vue提供的模板渲染语法中,除了支持简单的数据值之外,还可以可以进行javascript表达式的运算
    
        
        
{{ num +6 }}
{{ 5 > 4 ? 6 : 10}}
{{str.split("").reverse().join("")}}
8-3、事件绑定指令
1、v-on事件绑定:为DOM元素绑定事件监听,
   语法格式 v-on:事件名称="事件函数的名字"
    
2、绑定事件并传参:绑定方法的时候可以加小括号,可以不加,如果要传递参数,就加小括号
    
{{ num }}
3、v-on的简写形式:@ 语法格式 @事件名称="事件函数的名字" 4、其他事件把原生事件的on去掉 kyeup click 5、如果没有传递参数,那么我们默认可以接收到一个事件对象:e Document
6、可以通过这个事件对象获取到绑定事件的元素,然后对该元素进行修改
7、但是这样写太复杂了,所以vue给我们提供了一个内置变量:$event,就是原生的事件对象 通过绑定函数的时候传递进去,函数就会接收到这个事件对象,固定写法 8、事件修饰符:阻止默认事件的发生 以前:在函数里面写 e.preventDefault() 现在:在绑定事件的后面写 .prevent 1、 阻止跳转
run(e){ e.preventDefault(); console.log("阻止成功"); }, 2、 事件修饰符阻止跳转 jump(){ console.log("阻止成功"); } 9、因为调用e.preventDefault和e.stopPropagation是常见需求,所以vue提供了事件修饰符的概念,来帮助程序员更方便的对事件的触发进行控制。常见的5个事件修饰符如下: .prevent:阻止默认行为 .stop:阻止事件冒泡 .once:只触发一次 .self:只有在触发对象是当前元素自身触发时触发事件处理函数 .caputre:以捕获模式触发当前的事件处理函数 10、按键修饰符:在监听键盘事件的时候,我们经常需要判断详细的按键,可以为键盘相关的时间添加按键修饰符,例如:
8-4、双向绑定指令
1、vue提供了v-model双向数据绑定指令,快速获取表单的数据
2、双向绑定之后,vue的数据会随着表单的改变发生改变
       
        
{{username}}
3、v-model指令只能和表单元素进行使用 1、input输入框 2、select 3、textrea 4、为了方便对用户输入的内容进行处理,vue为v-model提供了3个修饰符 .number:将用户的输入值转为数值类型 + ={{n+s}} .trim:自动过滤用户的收尾空白字符 .lazy:在change时而非input时更新,在中间更新的时候不会改变,用的很少

8-5、条件渲染指令

1、条件渲染指令用来控制DOM的显示与隐藏。有两个条件渲染指令:
   v-if
   v-show
   
    6
    5

     

6 5 2、v-if 是通过让元素下树,隐藏该元素。动态的添加或移除元素,而v-show是通过style样式的display来隐藏或显示元素,如果要频繁的切换元素的显示形态,用v-show更好,如果有些元素不需要被展示,那么就用v-if。 3、 在实际开发中,不用考虑性能问题,直接使用v-if 4、还有一个v-else-if、v-else指令,v-else-if必须个v-if搭配使用,不然不会被识别
插件
1、vue 3 sinppets:
2、vetur:
3、yyr
8-6、列表渲染指令
1、v-for:列表渲染指令,基于一个数组来循环渲染一个列表结构,v-for需要用到iteminitems形式的特殊语法
  items是循环的数组
  item是循环数组的每一项元素
   
  • {{item}}
  • arr:["xiao","hong","lan","ming"] 2、谁在循环就给谁加v-for。 3、v-for还支持一个可选的第二参数,即当前项的索引,语法格式为(item,index) in items.
    • 索引{{index}} {{item.name}}
    4、官方建议,如果用到了v-for指令,那么一定要绑定一个 :key 属性,可以把index作为key值。必须是字符串或者数字类型,而且key值不允许重复,不然会报错,最好是把id值作为key值,因为key值要求具有唯一性
    • 索引{{index}} {{item.name}}
    5、56-62跳过

    9、过滤器

    9-1、了解过滤器
    1、过滤器(Filters):用于文本的格式化,可以用在两个地方,插值表达式和v-bind属性绑定,只能在vue3里面使用
    2、过滤器应该被添加在javascript表达式的尾部,由管道符进行调用,管道符就是竖线 |
    3、过滤器函数必须被定义在filters这个节点下面,这个节点对象和data平级,过滤器本质是一个函数,自己定义。过滤器中一定要有一个返回值。主要是为了进行文本的格式化,所以过滤器函数的传递的参数都是管道符前面那个值
         
            {{ msg | capi }}
           
    
    4、注意点:
        1、要定义到filters节点下,本质是一个函数
        2、在过滤器函数中,一定要有return,也就是返回值
    
    9-2、全局过滤器和私有过滤器
    1、定义在vue中的filters是私有过滤器,只能在当前的vue实例中使用
       
    
        
    {{ msg | capi }}
    //使用不了这个capi过滤器,因为是定义在vm里面的,属于私有过滤器 {{ msg | capi }}
    2、被定义在vm实例里面的过滤器只能在当前所控制的el区域使用,如果希望在多个vue实例之间共享过滤器,则 可以按照下面面的格式定义全局过滤器 Vue.filter()方法接收两个参数, 1):是全局过滤器的名字 2):全局过滤器的处理函数
    {{ msg | capi }}
    {{ msg | capi }}
    3、如果全局过滤器和私有过滤器名字冲突,按照就近原则,优先使用私有过滤器 4、可以连续的使用多个过滤器 {{ msg | capi | capi2 }} 表示递增使用,后面一个过滤器使用前面一个过滤器使用后的结果 5、因为过滤器是函数,可以接收参数,但要注意,接收参数的时候要从第二个位置开始,因为第一个是接收的管道符的文本 6、vue3是没有过滤器的 7、yyr

    10、侦听器

    10-1、侦听器了解
    1、侦听器:watch,监听数据的变化,针对数据的变化做特定的操作,侦听器本质上也是一个函数,监听谁就去watch里面定义一个和变量名字一样的函数,并做出响应。watch和data、methods是平级关系,表示
       监听数据的变化
       
    
        
    {{num}}
    2、侦听器的函数里面可以有两个参数,分别是变量的新值和旧值 watch:{ num(newval,oldval){ console.log("num发生变化"); console.log(oldval); console.log(newval); } } 3、侦听器的格式分为: 1)、方法格式的侦听器 缺点:无法在刚进入页面的时候,自动触发 如果侦听的是一个对象,对象的属性发生变化不会触发监听 2)、对象格式的侦听器 优点:可以通过immediate选项让侦听器自动触发一次 可以通过deep选项深度监听 4、最好使用方法格式的,简单一点
    10-2、深度监听
    1、 对象格式的监听器可以通过deep:true这个属性监听对象的属性的改变,任何一个对象的属性发生改变都会触发这个监听器。而这是方法格式的监听器是做不到的
    
    <body>
        <div id="app">
    
    
           <input type="text" v-model="student.name">
    
        </div>
        <script>
            const vm = new Vue({
    
                el: "#app",
                data: {
                    student:{
                        name:"小红",
                        age:18,
                        score:99
                    }
    
                },
               
                watch:{
    
                //   对象格式的监听器可以通过deep:true这个属性
                // 监听对象的属性的改变
                    student:{
                        handler(){
                            console.log("student发生变化");
    
                        },
                        deep:true
                        
    
                    },
                   
                }
            })
    
    
    
        </script>
    </body>
    2、方法格式监听对象的子属性的变化,必须包裹一层单引号。
       'student.name'(){
                        console.log("'student.name'发生变化");
                    }
    

    11、计算属性

    11-1、了解计算属性
    1、计算属性是指通过一系列的运算后,最终得到一个属性值。这个动态计算出来的属性值可以被模板结构或methods方法使用
    2、computed和el,data都是平级,都是属于vm这个实例对象的。是以对象的形式书写的。所有的计算属性都要定义到computed节点下面,计算属性在定义的时候,要定义成”方法格式”
    3、使用说明:
      1、这个计算属性是计算某个具体的变量,是一个函数方法,我们要把它定义在computed里面。
      2、这个函数方法有一个返回值,
      3、直接使用这个函数,把他当做一个变量来使用,它的返回值就是计算的那个变量的值
       
    
        
    {{gaibian }}
    4、声明的时候是方法格式,使用的时候是变量格式 好处:1)、实现代码的复用, 2)、只要计算属性中的数据源发改变,使用到的计算属性也会改变
    模板字符串
    模板字符串语法:
    	es5写法:
    		需要使用大量的“”(双引号)和 + 来拼接才能得到我们需要的模版
    		实例:
    			"He is " + person.name + " and we wish to know his" + person.age + ".That is all" 
        
    	es6写法:
    		用`(反引号)标识,用${}将变量括起来
    		实例:
    			`He is  ${person.name}  and we wish to know his ${person.age} .that is all`
       就是说,用``反引号将整句话包裹进去,然后把变量用${}包裹
          {{`He is ${age}`}}
    
            <br>
            <br>
    
            {{ `${name} 已经 ${age} ,她的身高 ${h}`  }}
     
    
    <!-- 属性渲染 -->
    
            <div :style="`background:rgb(${r},${g},${b})`"></div>
    
       
    

    12、axios

    1、axios是一个专注于数据请求的库,就是简化封装了ajax和promise的一个库,vue和react都会用这个
    
        
    {{res}}
    2、axios请求数据时,可以通过传递的参数获取自己想要的数据,传递参数使用data:{} const res = await axios.get("http://www.zt-it.com:5000/student", { params:{} }) 3、axios的方法:axios.get() ,axios.post(),axios.delete(),axios.put()

    13、Vue-cli

    13-1、单页面应用程序
    1、单页面就是一个Web网站里面只有一个唯一的一个html页面,素有的功能与交互都在这个唯一的一个页面内完成。
    2、vue-cli是vue.js开发的标准工具,简化了程序员基于webpack创建工程化的vue项目的过程
    3、中文官网地址:https://cli.vuejs.org/zh/
    4、vue-cli是npm上的一个全局包,可以使用npm install命令安装
    5、通过 vue create  项目的名称 就可以创建项目,最后一个表示让你自己手动选择需要的环境,然后进入下一步,*表示已经选择,第一项必须选择,表示vue的版本。按下空格键选择。eslint规定格式很严格,最好别选,bavel选择在独立的配置文件中
    
    
    13-2、项目文件结构
     git:    是一个为git客户端增加git工具,用于存储自己的版本库(或者叫.svn根据自己的配置会有不同名字的版本库)
    |- biuld:  vue2.0的配置,项目打包时候的配置文件(现如今的vue项目,可使用vue.config.js进行打包配置)
    |- node_modules: node的一些基础依赖包,可能还有拓展的安装的别的插件(npm install下载的依赖包,主要是根据package.json获取对应的依赖包)
    |- public: 存放一些主要的打包文件,如index.html等等,可以放置一些需要在index.html配置的文件
    
    |- src:项目的主文件夹(vue是SPA单页面应用,可以看做是一个主页面的应用里面的内容组件详情可看vue 代码格式解析)
           |- assets:          资源文件,用于存放一些静态文件,如字体、图片、css样式之类的
           |- components: vue主要内容的公共组件,可以进行复用
           |- router:           设置路由,指定路由对应的组件
           |- route:            main.js中的router是通过router文件映射,而router下的index.js是项目链接的关键,通过设置路径将views中的vue文件关联起来
           |- main.js:项目的主js,全局使用的各种变量、js、插件都在此定义和引入;整个项目先加载src里的main.js,通过里面的app元素生成vue对象,再将router里面的路由加载进去,结果在app的vue中呈现
           |- app.vue:  项目的入口文件
           |- store:放置vuex需要的状态关联文件,设置公共的state等,是公共数据管理器,关联页面都可随时访问数据,是一个专为vue.js应用开发的状态管理模式,集中式存储管理应用的所有组件的状态
           |- test:              测试文件目录
    
    |- .editorconfig:  是用来帮助开发者定义和维护代码风格(行尾结束符、缩进风格等)editorconfig配置文件网
    |- .env: 全局默认配置文件,无论什么环境都会加载合并
    
    .env.development:开发环境下的配置文件
    .env.development: 开发环境下的配置文件
    npm run serve(或者npm run dev 主要看 package.json) 会合并 .env 文件
    .env.production: 生产环境下的配置文件
    npm run build 会合并 .env 文件
    |- .eslintignore:        指定忽略的文件,不需要eslint校验文件; eslint校验对不符合规范代码报错
    |- .eslintrc.js:           eslintrc的配置文件,vue项目自带的文件,各个eslint配置项的作用;ESlint是一个检查代码的工具
    |- .gitignore: 可以避免在提交代码时把我们不想上传的文件提交到git中; LICENSE:开源协议的说明
    |- package.json:     记录作者、项目入口、项目描述、项目依赖等相关信息
    |- pnpm-lock.yaml: 记录详细的依赖版本
    |- postcss.config.js:插件,利用js插件对CSS进行转换
    |- prettier.config.js: 配置文件,保持代码风格统一
    |- README.md:     项目用的到的所有插件的json格式
    |- stylelint.config.js:让CSS样式代码在编辑、保存、提交git的时候按规范进行检查及美化
    |- tsconfig.json:      配置文件
    
    
    13-2-1、项目外部文件
    1、.gitignore:不接受git管理的文件或文件夹
    2、babel.config.js:babel的控制文件。
    3、package.json:配置的各种信息,依赖、各种信息。
       build:构建,最后一次编译,编译成html、js
       lint:进行语法检查
    4、package-lock.json:包版本控制文件。
    
    13-2-2、src
    1、assets:存放项目的静态资源文件夹,比如:css样式表、图片资源
    2、components:程序员封装的、可复用的组件。
    3、main.js是项目的入口文件,整个项目的运行,要先执行main.js
    4、app.vue 项目的主页,被main.js渲染到public的index.html文件里面
    
    13-2-3、main.js构成:项目最先运行,渲染App组件
    1、导入vue,得到vue构造函数
      import Vue from 'vue'
    
    2、导入App.vue这个根组件,要把模板解构渲染到html页面中
      这个组件是所有组件的父组件。受vm管理
      import App from './App.vue'
      
    3、关闭vue的生产提示
     Vue.config.productionTip = false
    
    4、创建Vue的实例对象
     new Vue({
       //把render函数指定的组件渲染到html文件中
       //mounet是挂载,相当于:el:“#app”
       render: h => h(App),
     }).$mount('#app')
    
    
    // 引入残缺版的vue,残缺版的vue不能自己渲染页面
    // 只有完整版的vue能够渲染,
    // vue由两部分组成:核心(生命周期、路由)+模板解析器
    // 节省空间,残缺版去掉了模板解析器,通过render函数
    // 去渲染页面
    import Vue from 'vue'
    import App from './App.vue'
    
    Vue.config.productionTip = false
    
    new Vue({
    
      //render:渲染
      
    //  h是一个函数,
    // h去渲染元素
    
      render: h => h(App),
    
    
    }).$mount('#app')
    yyr
    651908398
    
    13-2-4、App.vue
    1、所有组件的根组件
    2、整个项目只有一个vm实例,就在app.vue创建。
    3、用来编写待渲染的模板结构,index.html中预留一个el区域,让main.js把app.vue渲染到了index.html预留的区域中
    
    13-2-5、index.html配置
    DOCTYPE html>
    <html lang="">
      <head>
        <meta charset="utf-8">
        
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        
        <meta name="viewport" content="width=device-width,initial-scale=1.0">
        
        <link rel="icon" href="<%= BASE_URL %>favicon.ico">
        
        <title><%= htmlWebpackPlugin.options.title %>title>
      head>
      <body>
        
        <noscript>
          <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.strong>
        noscript>
        
        <div id="app">div>
        
      body>
    html>
    
    
    13-2-6、改变入口文件
    1、 https://cli.vuejs.org/zh/config/#pages
    2、 创建一个vue.config.js文件,然后再去官网的配置参考里面找到pages,选择代码
    粘贴到创建的文件里面,去掉多余的
      module.exports = {
        pages: {
          index: {
            // page 的入口
            entry: 'src/index/peiqi.js',
         
          }
        }
      }
    
    13-2-7、关掉语法检查
    1、 https://cli.vuejs.org/zh/config/#pages
    2、 创建一个vue.config.js文件,然后再去官网的配置参考里面找到lintOnSave,把配置拿过 lintOnSave:false 
       module.exports = {
        pages: {
          index: {
            // page 的入口
            entry: 'src/index/peiqi.js',
         
          }
        },
        lintOnSave:false
      }
    
    13-2-8、vue单文件
    1、组件化开发:根据封装的思想,把页面上可重用的UI结构封装为组件,方便项目的开发和维    护
    2、vue是一个支持组件化开发的前端框架,组件的后缀名是.vue,
    3、vue文件的组成部分,组件是对UI结构的复用
         1、template:组件的模板结构,
         2、script:组件的javascript行为
         3、style:组件的样式
    4、export  defalut:默认导出,有引入就要有导出
    5、组件中的data必须定义为函数类型,返回一个对象,因为每个组件都有属于自己的数据,避免数组重复,所以每个组件的数据通过data这个函数得到自己的数据
    6、可以安装Vetur可以使用快捷键<得到vue文件的模板
    7、组件必须只能由一个根节点。
    
    13-3、组件之间的关系
    1、组件在被封装好以后,没有引入关系的时候,是相互独立的,不存在父子关系
    2、如果在使用组件的时候,根据彼此的嵌套关系,形成了父子关系、兄弟关系
    3、父组件引入子组件的步骤
        1:使用import语法导入需要的组件
        2、使用compoents节点注册组件  键值一样可以简写
        3、以标签的形式使用刚才注册的组件
    4、通过components注册是私有子组件
    5、使用 <右键可以直接生成vue组件
    6、组件分为私有组件和全局祖册组件
    
    13-3-1、使用@代替src的方法
    1、下载一个插件 Path Autocomplete
    2、选择 齿轮-设置-打开设置
    3、复制代码到最前面
       //导入文件时是否携带文件的扩展名
       "path-autocomplete.extensionOnImport":true,
       //配置@的路径提示
       "path-autocomplete.pathMappings":{
       "@":"${folder}/src"
       }
    4、然后就可以引入了
    import Self from '@/components/Self.vue'
    (案例:two)
    
    
    13-3-2、注册全局组件
    1、注册一次,全局都可以使用
    2、在vue项目的main.js入口文件中,通过Vue.component()方法,可以注册全局组件
        
      // 导入需要全局注册的组件
      import Self from '@/components/Self.vue'
    
      // 参数1:字符串格式,表示组件的”注册名称“
      // 参数2:需要背全局注册的那个组件
    
       Vue.component('MySelf',Self)
    3、注册完以后就可以通过注册名称直接引入这个组件了
    

    main.js文件

    // 引入残缺版的vue,残缺版的vue不能自己渲染页面
    // 只有完整版的vue能够渲染,
    // vue由两部分组成:核心(生命周期、路由)+模板解析器
    // 节省空间,残缺版去掉了模板解析器,通过render函数
    // 去渲染页面
    
    import Vue from 'vue'
    import App from './App.vue'
    
    Vue.config.productionTip = false
    
    // 导入需要全局注册的组件
    import Self from '@/components/Self.vue'
    
    
    // 参数1:字符串格式,表示组件的”注册名称“
    // 参数2:需要背全局注册的那个组件
    Vue.component('MySelf',Self)
    
    
    
    
    new Vue({
       render:h=> h(App)
    
    }).$mount('#app')
    
    

    14、组件之间的通信(分享数据)

    14-1、props(父组件给子组件传递数据->自定义属性)
    1、props:是组件的自定义属性,在封装通用组件的时候,合理的使用props可以极大地提高组件的复用性(自我总结:就是说每个组件(vue文件)都有这个属性。但如果这些文件的初始值不一样,而且被映射到一个文件上面,就可以使用props)
    (被引入的组件是子组件,引入组件的是父组件。在父组件里面把属性传给子组件,子组件使用   props接收)
    
    2、props的语法格式:
       props:["自定义属性1","自定义属性2"]
       是一个数组,和data等平级关系,里面的属性用字符串包裹
       
    3、子组件使用props接收父组件的步骤:(父组件是App.vue,子组件是father.vue)
        1、在引入组件的时候,在父组件里面使用子组件的标签对里传值   
        <Father :count="count"></Father>
        2、在子组件里面接收
         props:['count']
        3、使用这个属性   
     注意:子组件的这个属性改变不会影响到父组件的属性发生改变
        
    4、 props可以传递具体的值,也可以传变量,是自定义属性。在传值的时候为当前组件指定初始值。这个自定义属性是封装者自己定义的。可以极大地提高组件的复用性
    
    5、props传递变量的三种方式
      1、传递的是字符串
          <Son count="9"></Son>
      2、传递的是数值
         <Son :count="9" ></Son>
      3、传递的是变量
        <Son :count="count" ></Son>
     因为 :代表v-bind,里面是js语句,相当于count=9
    
    6、props的数据,可以直接在模板结构中被使用,并且,子组件不要修改props接收到的值,会报错。
    
    7、vue规定,组件中封装的自定义属性是只读的,程序员不能直接修改props的值,不然会直接报错。
    
    8、可以把props值传给data
        num:this.count
    
    9、props的default值,来定义属性的默认值。写成对象的形式,一般是在组件没有传递该属性时候,则默认值生效
          props:{
            count:{
                default:5
            }
        }
    
    10、props的type值类型,设置属性的类型,传入的值必须是该类型
           props:{
            count:{
                default:5type:Number
            }
        }
    
    11、props的required:必填,要求必须传递该属性的值
           props:{
            count:{
                default:5,
                required:true
            }
        }
    
    12、简答类型复制的是值,复杂类型的是引用地址。
    
    13、yyr
     
    
    14-2、子组件向父组件传递数据(使用自定义事件)
    1、子组件可以通过自定义时间向父组件传递数据。
       1、在子组件中自定义一个事件,使用 this.$emit('btn-click', item)的语法,emit指代发射事件,btn-click是我们自定义的事件名,item是子组件中的数据。 注意::vue官方推荐你始终使用 kebab-case格式的事件名。
       
       2、在父组件中使用v-on监听在子组件中我们自定义的数组,并为其在父组件中定义一个接收监听的事件
       
       3、在父组件中接收数据
    
    
        
    
         methods: {
            add(){
                this.$emit('num',this.message)
            }
        },
    
    
        
     methods: {
        add(n){
    
          console.log(n);
        }
      },
    
    14-3、兄弟组件之间的数据共享(EventBus:全局事件总线,可实现任意组件通信)
    1、创建一个eventBus.js模块,并向外共享一个Vue的实例对象
    
    2、在数据发送方,调用bus.$emit("事件名称",要发送的数据)方法触发自定义事件
    
    3、在数据接收方,调用bus.$on("事件名称",事件处理函数)方法注册一个自定义事件
    
    1、自定义一个eventBus.js
       import Vue from 'vue'
    
      export default new Vue()
    
    2、在数据发送方,引入这个文件。再定义一个事件,然后通过这个事件调用bus.$emit("事件名称",要发送的数据)方法触发自定义事件
       
    
    
    
    3、在数据接收方,使用create生命周期函数调用bus.$on("事件名称",事件处理函数)方法注册一个自定义事件
    
    
    
    
    
    14-4、vuex(状态管理)
    vuex官方解释
    Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
    
    14-4-1 、vuex的概念
    1、概念:专门在vue中实现集中式状态(数据)管理的一个插件 Vue.use()。对vue应用中的多个组件的共享状态进行集中式状态 数据  管理(读/写)。也是一种组件间通信的方式,且适合用于任意组件间的通信
    
    14-4-2、什么时候使用vuex(共享)
    1、多个组件依赖于统一状态(多个组件需要用到同一个数据,就可以让vuex来管理这个护具)
    
    2、来自不同组件的行为需要变更同一状态(需要改变这同一个数据)
    
    
    14-4-3、vuex工作原理图

    学习Vue这一个就够_第2张图片

    每一个 Vuex 应用的核心就是 store,里面又包括:
    
    1. State(状态):用于数据的存储(对象类型数据),是store中唯一数据源
    
    2. Actions(行为):类似于mutation,用于提交mutation来改变状态,而不直接变更状态,可以包含任意异步事件
    
    3. Mutations(转变):类似函数,改变state数据的唯一途径,且不能用于处理异步事件。
    
    Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方
    
    4. Getter(数据加工):如vue中的计算属性一样,基于state数据的二次包装,常用于数据的筛选和多个数据的相关计算
    
    5. Module:类似于命名空间,用于项目中将各个模块的状态分开定义和操作,便于维护
    
    由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块。
    
    
    vuex工作原理说明
    1、,actions、mutations,state
    
    2、actions:动作、行为
    
    3、mutations:维修,加工
    
    4、state:状态,把数据交给vuex的state对象进行保管。
    
    5、dispatch:分发,派遣。
    
    14-4-4、vuex的搭建环境
    1、安装vuex
       npm i vuex@3
       
    2、在main.js里面设置vue.use(Vuex)
      import Vuex  from 'vuex'
      //就可以配置store项
     Vue.use(Vuex)
    
    3、在src里面创建一个文件夹store,创建一个index.js
       用于创建vuex中最核心的store,
       在js文件里面创建三个对象   
      
      // 准备actions-用于响应组件中的动作
       const actions={}
    
      // 准备mutations-用于操作数据
      const mutations={}
    
       // 准备dtate-用于存储数据
      const  state={}
     
      然后创建一个store对象来管理这几个对象
      因为store是通过Vuex的Store创建的。所以我们要引入Vuex
      // 引入Vuex创建store
      import Vuex from 'vuex'
    
      然后创建store
       const store =new Vuex.Store({
        actions,
        mutations,
        state
    
    })
    
    // 向外暴露,因为主要是要的是store,所以暴露的是store
    export default store
    
    
      
    4、在main.js引入这个store,所有的组件对象能看见这个 store
       // 引入store
      import store from './store'
      //配置
      
    new Vue({
      el:"#app",
      store,
    
      //render:渲染
      
    //  h是一个函数,
    // h去渲染元素
    
    render:h=> h(App)
    
    })
    
    5、报错,现这样错误的原因是在创建store实例之前,没有调Vue.use(Vuex),但这个时候会有人说,已经调用了Vue.use(Vuex),还是会出现这样的错误。究其原因是因为Vue脚手架会解析文件中的所有import语句,然后把所有import语句按照编写代码的顺序全都汇总在最上方,之后才会解析文件中的其它代码,这就会使得Vue.use(Vuex)在store实例之后执行。
     import引入最高级,会优先执行import的js,所以先创建store实例会报错。
    
    6、解决:在store.js,引入Vue后,在使用Vue.use(Vuex)
      import Vue from 'vue'
       Vue.use(Vuex)
    
    620227月,vue3成为了默认版本, 现在npm i vue,安装的就是vue3,vue3成为默认版本,vuex也更新到了44只能在vue3中使用,现在使用npm i vuex安装的是4版本
    我们项目使用的是2版本,使用vuex4就会报错。所以我们要安装3版本
    

    store.js

    // 引入Vuex创建store
    import Vuex from 'vuex'
    
    
    // 准备actions-用于响应组件中的动作
    const actions={}
    
    // 准备mutations-用于操作数据
    const mutations={}
    
    // 准备dtate-用于存储数据
    const  state={}
    
    
    // 创建store
    // 因为store是管理
    
    // const store =new Vuex.Store({
    //     actions,
    //     mutations,
    //     state
    
    // })
    
    // 向外暴露,因为主要是要的是store
    // export default store
    
    
    // 简写,创建并暴露store
    export default new Vuex.Store({
        actions,
        mutations,
        state
    
    })
    

    main.js

    // 引入残缺版的vue,残缺版的vue不能自己渲染页面
    // 只有完整版的vue能够渲染,
    // vue由两部分组成:核心(生命周期、路由)+模板解析器
    // 节省空间,残缺版去掉了模板解析器,通过render函数
    // 去渲染页面
    import Vue from 'vue'
    import App from './App.vue'
    // 引入vuex
    import Vuex from 'vuex'
    // 引入store
    import store from './store'
    
    Vue.use(Vuex)
    
    Vue.config.productionTip = false
    
    
    
    new Vue({
      store,
      render:h=> h(App)
    }).$mount('#app')
    
    
    解决报错

    store.js

    // 引入Vuex创建store
    import Vuex from 'vuex'
    // 引入vue
    import Vue from 'vue'
    
    
    // 准备actions-用于响应组件中的动作
    const actions={}
    
    // 准备mutations-用于操作数据
    const mutations={}
    
    // 准备dtate-用于存储数据
    const  state={}
    
    Vue.use(Vuex)
    
    // 创建store
    // 因为store是管理
    
    // const store =new Vuex.Store({
    //     actions,
    //     mutations,
    //     state
    
    // })
    
    // 向外暴露,因为主要是要的是store
    // export default store
    
    
    // 简写,创建并暴露store
    export default new Vuex.Store({
        actions,
        mutations,
        state
    
    })
    

    main.js

    // 引入残缺版的vue,残缺版的vue不能自己渲染页面
    // 只有完整版的vue能够渲染,
    // vue由两部分组成:核心(生命周期、路由)+模板解析器
    // 节省空间,残缺版去掉了模板解析器,通过render函数
    // 去渲染页面
    import Vue from 'vue'
    import App from './App.vue'
    // 引入vuex
    import Vuex from 'vuex'
    // 引入store
    import store from './store'
    
    
    
    Vue.config.productionTip = false
    
    
    
    new Vue({
      el:"#app",
      store,
    
      //render:渲染
      
    //  h是一个函数,
    // h去渲染元素
    
    render:h=> h(App)
    
    
    
    
    
    })
    // .$mount('#app')
    
    
    14-4-5、vuex工作流程
    1、state管理数据,所以把想让vuex管理的数据保存到state中。
    
    2、当我们想改变state保管的数据的状态的时候。就使用action保管的函数方法,使用dispatch方法将执行那个函数方法拍给action执行。
      this.$store.dispatch('函数方法',参与运算的数据参数)
        this.$store.dispatch('Jia',this.num)
    
    3、action函数里面响应这个方法,所以需要在action里面定义这个函数方法,使用对象格式,也可以简写,这个函数方法可以接收到两个参数,一个是context,这个上下文对象就包括了commit方法,可以
      函数方法名(context,n){
      函数体
      }
      
    4、action的这个函数方法可以接收到两个参数,一个是context,这个上下文对象就包括了commit方法,可以使用这个context对象调用commit方法,由 actions 提交一个 mutation。记住!!!这个函数方法名改为大写,为了区分mutation和action写的函数
     函数方法名(context,n){
      context.commit(‘函数方法名’,n){5、在mutation里面准备定义这个函数,也有两个参数,a是state,b是传递的参数数据
      就可以通过a.数据和数据进行处理
      mutation=大写的函数方法名(a,b){
           
              
          }
          }
    6、展示state里面的数据的写法
      $store.state.数据名
         
    7、actions决定业务逻辑是否调用mutation的函数,包括发送异步请求
    
    8、如果函数不需要什么业务逻辑,可以直接mutation对接,直接调用commit调用mutation里面的函数
      this.$store.commit('大写的函数方法名',参数数据)
    
         
    9、组件中地区vuex的数据,$stroe.state.sum 
         
    10、组件中使用actions的数据:$store.dispatch('action中的方法名',数据)
          $store.commit('mutation中的方法名',数据)
         (如果没有网络请求或起亚业务逻辑,可以绕过actions,直接commit)
    
    工作流程
    https://blog.csdn.net/JHY97/article/details/124045131?ops_request_misc=&request_id=&biz_id=102&utm_term=vuex%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86%E5%9B%BE&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-1-124045131.142^v87^control_2,239^v2^insert_chatgpt&spm=1018.2226.3001.4187
    
    14-4-6、vuex的getters
    1、getters其实就是store的计算属性,对state里面的状态进行过滤处理,用法与组件自身的计算属性一模一样。
    
    2、使用,和actions一样定义,然后和计算属性一样在里面定义方法,方法返回一个数值
      const getters={
        
      }
      然后把getters放到store里面
      export default newVVuex.Store({
      actions,
      mutations,
      state,
      getters
      }
      
    3、当state中的数据需要经过加工后再使用时,可以使用getters加工  
    
    14-4-7、vuex的mapState
    1、mapState是什么
       用于帮助我们映射state中的数据为计算属性
       因为我们可以在组件的计算属性的方法里面,直接返回state里面的数据,而
       this.$store.state.数据 。如果返回state数据的函数方法太多,太麻    烦。mapState可以帮我们生成这种函数方法
      
       
       使用:先在需要映射的组件里面引入这个组件
        import  {mapState} from 'vuex'
    
       在computed里面使用mapState生成函数方法
       mapState({方法名:"state里面的数据"})
    
      如果方法过多,我们可以解构的形式
      ...mapState({方法名:"state里面的数据",方法名2:"state里面的数据2"})
       
      简写,把数据名用字符串括起来放在数组里面
        ...mapState(['数据名1''数据名2'])
       
    2、mapGetters方法:用于帮助我们映射getters中的数据为计算属性
       和mapstate用法一致
    
    
    3、mapMutations方法:用于帮助我们生成与mutations对话的方法,即:包含          $store.commit(xxx)的函数
        和mapstate用法一致的话,会出错。传入的是鼠标事件,因为生成的函数没有参数,而mutation定义的参数里面是有value的,而默认是有一个事件对象,所以这个事件对象会在被作为value值传给mutations的value值
        ...mapMutations({方法名1:"mutations里面的方法1",方法名2:"mutations里面的方法12"})
       
      解决方法:在调用的时候,把这个数传过去
      方法名1(n)
      
    4、mapActions方法:用于帮助我们生成与actions对话的方法,即:包含                $store.dispatch(xxx)函数
        和mapMuatations用法一致
         
    
    14-4-8、vuex模块化
    1、因为会有不用的功能,比如订单模块,用户模块,可以把这些模块分成不同的对象,统一配置actions,state,mutations,
      const 对象1={
       const actions={}const state={}const mutations={}const getters={}
      }const 对象2={
       const actions={}const state={}const mutations={}const getters={}
      }
    
    
    2、暴露store的时候,去掉actions,state,mutations,使用modules放置定义的对象,这里的a,b是别名
      export default new Vuex.Store({
       modules:{
       a:配置对象1b:配置对象2
       }
    
    })
    
    3、简写,这样写的话,可以输出this.$store看一下
       export default new Vuex.Store({
       modules:{
       配置对象1,
       配置对象2
       }
    
    })
    
    
    4、计算属性使用的时候,这是将mapstate方法将a,b生成计算属性,将store的state下面的a,b作为计算属性的方法,返回这两个数据,因为它们是两个对象,所以可以使用a.属性名,b.属性名。
     ...mapState(['a','b'])
    
    5、直接从配置对象里面拿到数据,表示从别名1里面拿去数据,但是只是这样肯定会报错,还需要给配置对象设置一个namespaced:true属性
     ...mapState(‘别名1,['a','b'])
    
     const 对象1={
        namespaced:true,
       const actions={}const state={}const mutations={}const getters={}
      }6、方法也是一样
         ...mapMutations(‘别名1’,{方法名1:"mutations里面的方法1",方法名2:"mutations里面的方法1"})
         就可以调用这个方法,记得传参
    
    7、如果是直接调用commit方法,要找到具体的是哪一个配置对象的方法
      this.$store.commit('配置别名/配置方法名',传入的参数)
    
    8、获取配置对象的getters的方法
      this.$store.getters['配置别名/配置方法名']
    
    9、如果是直接调用dispatch方法,要找到具体的是哪一个配置对象的方法
      this.$store.dispatch('配置别名/配置方法名',传入的参数)
    
    10、模块化语法减少代码耦合,更好维护代码。让各种数据分类更加明确
    
    14-4-9、vuex的详细用法
    1、开启命名空间后,组件中读取state的数据
        1—自己直接读取
          this/$store.state.配置名.数据名
        2-借助mapState读取
          ...mapState('配置别名'['数据名1''数据名2'])
          
    2、开启命名空间后,组件中读取getters的数据
        1—自己直接读取
           this.$store.getters['配置别名/配置方法名']
        2-借助mapGetters读取
          ...mapGetters('配置别名'['方法名1''方法名2'])
    
          
    3、开启命名空间后,组件中调用dispatch
        1—自己直接dispatch
           this.$store.dispatch('配置别名/配置方法名',传入的参数)
        2-借助mapActions生成方法,方法调用需要传递参数
          ...mapActions('配置别名'['方法名1''方法名2'])
          或者
          ...mapActions('配置别名'{组件定义的方法名:'配置对象的方法名'})
          
    4、开启命名空间后,组件中调用commit
        1—自己直接commit
           this.$store.commit('配置别名/配置方法名',传入的参数)
        2-借助mapMutations生成方法,方法调用需要传递参数
          ...mapMutations('配置别名'['方法名1''方法名2'])
          或者
          ...mapMutations('配置别名'{组件定义的方法名:'配置对象的方法名'})    
    
    14-5、消息订阅
    个人省略
    

    15、组件之间的样式冲突问题

    1、默认情况下,写在.vue组件中的样式会全局生效,因此会很容易造成多个组件之间的样式冲突问题。原因是因为
        1、单页面应用程序,多有组件的DOM结构,都是基于唯一的index.html进行呈现
        2、每个组件中的样式,都会影响整个index.html中的DOM元素
    2、解决样式冲突问题
       在style里面加上scoped,vue会自动为该组件的元素生成私有属性
       
         
    3、如果想在父组件里面改变子组件的样式,而其他引入了子组件的不会发生改变,那么,不仅要在该父组件定义scoped,还要在改变的样式前面加上一个前缀,这样的话就会变成一个后代选择器。
         /deep/ div{
        width: 200px;
        height: 200px;
        background-color: blue;
       }
    
    

    16、生命周期

    16-1、简单介绍
    官网:每一个vue实例从创建到销毁的过程,就是这个vue实例的生命周期。在这个过程中,他经历了从开始创建、初始化数据、编译模板、挂载Dom、渲染→更新→渲染、卸载等一系列过程。
    
    1、生命周期:是一个vue组件从  创建 ->运行->销毁  的整个阶段,强调的是一个时间段
    
    2、生命周期函数:是vue提供的内置函数,会伴随着组件的生命周期,自动按次序执行
    
    3、生命周期强调的是时间段,生命周期函数强调的是时间点
    
    4、组件创建阶段: beforeCreate(组件还没开始创建之前)、created(内存里面创建好,还没被渲染)、beforeMount(将要渲染的时候)、mounted(渲染好的时候,刚好看到组件的时候)
    
    5、组件运行阶段:beforeupdate(组件更新前)、updated
    
    6、created最重要,因为我们异步请求数据就是在这个周期函数里面
    
    
    1、创建期间的生命周期函数:
      1)beforeCreate:实例刚在内存中被创建出来
        此时还未初始化完毕data和methods
      2)created:实例已经在内存中创建完毕
        此时 data和methods已经创建完毕 但此时还未开始编译模板
      3)beforeMount:此时已经完成模板的编译
        但是还未挂载到页面中
      4)mounted:此时已将编译好的模板挂载到了页面指定的容器中显示
    2、运行期间的生命周期函数:
      1)beforeUpdate:状态更新之前执行此函数
        此时data中的状态值是最新的 但界面上显示的数据还是旧的
        因为此时还未开始重新渲染DOM节点
      2)updated:实例更新完毕之后调用此函数
        此时data中的状态值和界面上显示的数据都已完成了更新 界面已被重新渲染好了
    3、销毁期间的生命周期函数:
      1)beforeDestroy:实例销毁前调用
        在这 实例仍然完全可用
      2)destroyed:Vue实例销毁后调用
        调用后 Vue实例指示的所有东西都会解除绑定 所有的事件监听器会被移除 所有的子实例     也会被销毁
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ISgI4l6Z-1686141820663)(C:\Users\Direct\Desktop\常用前端框架及工具\拓展学习资料\生命周期函数.png)]

    组件创建阶段
    
    
    
    
    
    
    组件运行阶段
    
    
    
    
    

    17、ref引用(Vue用来操作DOM元素的)

    1、ref是用来辅助开发者在不依赖jquery的情况下,获取DOM元素或组件的引用
    
    2、每个vue的组件实例上,都包含一个$refs对象,里面存储着对应的DOM元素激活组件的引用。默认情况下,组件的$refs指向一个空对象
    
    3、给一个Dom元素定义一个ref属性,然后取一个名字,就可以通过$refs.名字对这个DOM元素进行操作
    
    4、如果想要使用ref引用页面上的组件实例,还可以给组件使用ref。然后通过this.$refs.组件的ref的名字.fn(),就可以运行该组件的方法
    
    
    
    
    
        
        
        
        Document
        
    
    
    
        
    使用ref操作dom元素
    根组件引用Ref组件过后,通过ref属性使用他的方法
    
    
    
    
    
    17-1、this.$nextTick()方法
    1、this.$nextTick()方法主要是用在随数据改变而改变的dom应用场景中,
       vue中数据和dom渲染由于是异步的,
       所以,要让dom结构随数据改变这样的操作都应该放进this.$nextTick()的回调函数中。
    
    2、created()中使用的方法时,dom还没有渲染,如果此时在该钩子函数中进行dom赋值数据(或者其它dom操作)时无异于徒劳,
    所以,此时this.$nextTick()就会被大量使用,而与created()对应的是mounted()的钩子函数则是在dom完全渲染后才开始渲染数据,
    所以在mounted()中操作dom基本不会存在渲染问题。
    
    3、就是数据发生改变了,但是页面还没有反应过来,就需要使用这个this.$nextTick(),等待数据渲染后应用在dom里面,需要dom重新渲染的时候就需要用到这个方法。把回调推迟到下一个DOM更新周期之后执行
    
    this.$nextTick(()=>{
      函数体
    })
    

    18、动态组件

    1、动态组件指的是动态切换组件的显示和隐藏
    
    2、vue提供了一个内置的<component>组件,专门用来实现动态组件的渲染,作用:组件的占位符,is属性的值:表示要渲染的组件的名字。而且,is属性的值,应该是组件在components节点下的注册名称。也就是必须是引入的组件,注册过后,才能使用。
    
    3、可以把这个<component>看做一个组件的占位符。但是直接使用会报错,未知的元素错误,因为这个元素还没有被定义。
    
    4、在component组件里面使用is属性选择要渲染的组件
      
       <component is="Hello">component>
       <component is="Hi">component>
        
    5、对于飘红线显示错误的情况,使用v-bind绑定is属性,然后使用反引号括起来组件名字
           <component :is="`Hello`">component>
           <component :is="`Hi`">component>
        
    6、组件的切换,会不断的创建和销毁,字符串的值用单引号括起来,is属性绑定str
     <div id="app">
        <nav>App根组件
     
          <button @click="str = 'Hello'">切换为Hello组件button>
       
          <button @click="str = 'Hi'">切换为Hi组件button>     
        nav>
        <component :is="str">component>
        
      div>
    
    7、使用keep-alive保持让组件隐藏的时候不会被销毁,直接使用<keep-alive>keep-alive>标签将切换的动态组件括起来
          <div id="app">
            <nav>App根组件
     
             <button @click="str = 'Hello'">切换为Hello组件button>
       
            <button @click="str = 'Hi'">切换为Hi组件button>           
        nav>
              
          <keep-alive>
             <component :is="str">component>
          keep-alive>
        
      div>
        
    8、打开vue调试工具,在切换inactive表示被缓存了,没有被销毁
    
    9、如果想在组件被缓存的时候做什么,在组件被激活的时候做什么,有对应的生命周期函数
          当组件被缓存的时候,会自动触发组件的deactivated生命周期函数
          当组件被激活的时候,会自动触发组件的activated生命周期函数
    created() {
        console.log("Hello组件已经创建");
      },
      destroyed() {
        console.log("Hello组件已经销毁");
      },
      deactivated() {
        console.log("Hello组件缓存");
      },
      activated (){
        console.log("Hello组件激活");
      }
    
    10、组件第一次被创建的时候,会激活created,也会激活activated生命周期,组件被激活的时候只会触发activated,不再触发created。
        
    11、keep-alive的include属性:在component会把component包裹的组件都缓存起来。可以使用include属性用来指定。至于名称相匹配的组件会被缓存,多个组件名之间使用,就是说用它来指定哪些组件需要被缓存,多个组件名之间用,分隔。不被包含在里面的都不会被缓存,记住这个include指定的组件名是在组件里面的定义的name属性
        //只有Hello组件可以被缓存
      <keep-alive include="Hello">
          <component :is="str">component>
        keep-alive>
        
    12、exclude属性:默认哪些组件不会被缓存,不能和include同时使用   
        
    13、在组件提供了name属性后,组件的名称就是name属性的值。如果在“声明组件”的时候,没有为组件指定name名称,则组件的名称默认就是“注册时候的名称”,
        
    14、注册名称以标签的形式使用,把注册好的组件渲染和使用到页面结构中
        name名称为了在调试工具里面看到组件名称,以及结合《keep-alive》实现组件缓存功能
    

    Hello子组件

    <template>
      <div>
      
        Hello组件
    
      div>
    template>
    
    <script>
    export default {
      created() {
        console.log("Hello组件已经创建");
      },
      destroyed() {
        console.log("Hello组件已经销毁");
      },
      deactivated() {
        console.log("Hello组件缓存");
      },
      activated (){
        console.log("Hello组件激活");
      }
    }
    script>
    
    <style lang="less" scoped>
    div{
      width: 100%;
      height: 400px;
       position: absolute;
      top:58px;
      background-color: rgb(248, 245, 49);
    }
    
    
    style>
    

    父组件

    <template>
      <div id="app">
        <nav>App根组件
     
          <button @click="str = 'Hello'">切换为Hello组件button>
       
          <button @click="str = 'Hi'">切换为Hi组件button>
          
         
        
          
        nav>
        <component :is="str">component>
        
      div>
    
    
    template>
    
    <script>
    
    import Hello from './components/Hello.vue'
    import Hi from './components/Hi.vue'
    
    export default {
      name: "App",
      components: {
        Hello,
        Hi,
    
    
    
      },
      data() {
        return {
          str:""
    
        }
      }
    
    };
    
    script>
    <style lang="less" scoped>
    * {
      padding: 0;
      margin: 0;
    }
    
    nav {
      width: 100%;
      height: 50px;
      background-color: #eee;
    }
    style>
    

    Hi子组件

    <template>
        <div>
    
            Hi组件
    
        div>
    template>
      
    <script>
    export default {
    
    }
    script>
      
    <style lang="less" scoped>
    div {
        width: 100%;
        height: 400px;
    
    
    
        background-color: orange;
    }
    style>
    

    19、插槽

    19-1、插槽的基本用法
    1、插槽(slot)是vue为组件的封装这提供的能力,允许开发者在封装组件的时候,把不确定、希望由用户指定的部分定义为插槽。
    
    2、简单来说就是在使用注册过的组件时,如果要往那个标签对里面插入什么元素,但是不会显示出来,就可以往子组件里面写一个插槽,这样这个组件标签对里面写的东西就可以显示出来了
    
    3、用户使用什么,插槽就渲染什么
    
    4、vue官方规定,每一个插槽都应该有一个name名称,如果没有定义会有一个default的默认名称
         <slot name="p">slot>
    
    5、如果插槽定义了name属性,那么我们要使用 v-slot:插槽的名字,去指定是哪一个插槽,而且要注意的是,这个被指定要使用插槽的元素要使用template包裹。
      例如:根组件引用了Hello组件,在标签对里面使用了一个p标签,然后,在hello组件里面定义了一个name属性为p的插槽,然后根组件就需要将这个p标签用template包裹起来。然后在template里面定义v-slot:p
      Hello组件
       <slot name="p">slot>
      App组件
       <Hello>
            <template v-slot:p>
              <p >你好,这是插槽内容p>
            template>
          Hello>
        
    6、注意:
        1、如果要把内容填充到指定名称的插槽中,需要使用v-slot
        2、v-slot值只能用在template身上,而且渲染的页面是看不见这个template元素的,只会看见被渲染的元素
        3、v-slot:插槽的名字
        4、插槽指令v-slot的简写形式是: #,就是一个#号
    
    1、比如,在APP根组件里面引入了Hello组件,然后声明注册后以标签对的形式使用,在里面定义了一个p标签,但不会显示内容,只有在Hello里面定义一个slot插槽,接收到这个p标签,才能显示内容
    
    普通的定义插槽

    根组件

    <template>
      <div id="app">
        <nav>App根组件
     
         
          <Hello>
            <p>你好,这是插槽内容p>
          Hello>
        
          
        nav>
     
        
      div>
    
    
    template>
    
    <script>
    
    import Hello from './components/Hello.vue'
    import Hi from './components/Hi.vue'
    
    export default {
      name: "App",
      components: {
        Hello,
        Hi,
    
    
    
      },
      data() {
        return {
          str:""
    
        }
      }
    
    };
    
    script>
    <style lang="less" scoped>
    * {
      padding: 0;
      margin: 0;
    }
    
    nav {
      width: 100%;
      height: 50px;
      background-color: #eee;
    }
    style>
    

    Hello组件

    <template>
      <div>
      
        Hello组件
        <slot>slot>
    
      div>
    template>
    
    <script>
    export default {
     
    }
    script>
    
    <style lang="less" scoped>
    div{
      width: 100%;
      height: 400px;
       position: absolute;
      top:58px;
      background-color: rgb(248, 245, 49);
    }
    
    
    style>
    
    有名字的插槽

    Hello组件

    <template>
      <div>
      
        Hello组件
        <slot name="p">slot>
    
      div>
    template>
    
    <script>
    export default {
     
    }
    script>
    
    <style lang="less" scoped>
    div{
      width: 100%;
      height: 400px;
       position: absolute;
      top:58px;
      background-color: rgb(248, 245, 49);
    }
    
    
    style>
    

    App组件

    <template>
      <div id="app">
        <nav>App根组件
     
         
          <Hello>
            <template v-slot:p>
              <p >你好,这是插槽内容p>
            template>
          Hello>
        
          
        nav>
     
        
      div>
    
    
    template>
    
    <script>
    
    import Hello from './components/Hello.vue'
    import Hi from './components/Hi.vue'
    
    export default {
      name: "App",
      components: {
        Hello,
        Hi,
    
    
    
      },
      data() {
        return {
          str:""
    
        }
      }
    
    };
    
    script>
    <style lang="less" scoped>
    * {
      padding: 0;
      margin: 0;
    }
    
    nav {
      width: 100%;
      height: 50px;
      background-color: #eee;
    }
    style>
    
    19-2、具名插槽和作用域插槽
    1、带名字的插槽就是具名插槽,
    
    2、slot插槽可以定义属性,在template里面用v-slot接收
      子组件:
          <slot name="p" msg="好好学习,天天向上">slot>
      根组件
            <Hello>
            <template #p="obj">
              <p >你好,这是插槽内容p>
              {{ obj }}
            template>
          Hello>
    
    3、在封装组件时,为预留的slot提供属性对象的值,这种用法叫做作用域插槽
    
    4、这种作用域插槽也是具名插槽,用v-slot接收,v-slot可以用#来进行简写。数据对象可以用=来接收。对象的名字用scope定义
           <Hello>
            <template #p="scope">
              <p >你好,这是插槽内容p>
              {{ obj }}
            template>
          Hello>
    
    5、作用域插槽可以使用解构接收数据对象
    写法:可以直接使用这个msg
      #p="{msg}"
    
    也可以通过scope直接接收所有数据
      #p="scope"
      {{scope.msg}}
    

    20、自定义指令

    1、vue官方提供了v-text、v-for、v-model等常用的指令,还允许开发者自定义指令
    
    2、vue的自定义指令分为两类:
        1)、私有自定义指令
        2)、全局自定义指令
    
    3、私有自定义指令:
         在每个vue组件中,可以在directives(自定义指令节点)节点下声明私有自定义指令
         就在组件实例里面定义,和methods、data等平级,这个指令是对象形式,定义的指令      也是对象形式
          // 这是自定义指令的节点
       directives:{
        // 定义一个color的指令,指向一个配置对象
          color:{
        // 当这个指令绑定到元素的时候,会马上触发bind函数
        // bind函数会接收一个el参数,这个el参数就是绑定的dom元素
           bind(el){
          console.log(el);
             }
          }
      }
    
    4、例如,定义一个color的指令,可以在绑定元素的时候,把元素的背景颜色渲染为绿色
         // 这是自定义指令的节点
      directives:{
        // 定义一个color的指令,指向一个配置对象
      color:{
        // 当这个指令绑定到元素的时候,会马上触发bind函数
        // bind函数会接收一个el参数,这个el参数就是绑定的dom元素
        // 可以利用这个el参数对Dom对象做操作,将背景颜色渲染为绿色
        bind(el){
          el.style.backgroundColor="green"
        }
    
      }
    
      }
    
    5、这种定义私有指令的时候,不用使用v-开头来定义,但是使用的时候必须使用v-开头,例如
      <div class="box" v-color>
      这是一个红色的盒子
      </div>
     
    6、自定义指令接收实际参数,会有一个binding对象。binding对象里面有一个value,可以接收到传入的数据,而且,,如果传入的数据时字符串格式的话,要记得给字符串加上单引号。不带引号传入的是一个变量。写法:
         <div class="box" v-color="'yellow'">
          这是带有参数的自定义指令
        </div>
    
      定义私有指令的写法
      directives:{ 
      color:{
        bind(el,binding){
          el.style.backgroundColor=binding.value
        }
      }
      }
    
    7、expreion:是一个表达式,就是这个=后面的表达式。代表用户写的东西。
    
    8、bind函数的缺点,只会在第一次绑定元素的时候执行,而且只执行一次,而如果页面数据更新,是无法改变的,二update函数会在每次Dom更新的时候调用。
       updated() {
          console.log(this.str);
        },
     
    9、凡是使用到了这个指令的元素,都会触发这个update函数
    
    10、update只会在数据更新的时候生效,不会在第一次的时候生效
    
    
    11、函数简写:
       如果bind和update函数中的逻辑完全相同,则对象格式的自定义指令可以写成函数格式:
        color(el,binding){  
          el.style.backgroundColor=binding.value
      
    }
     
    12、私有自定义指令只能在当前定义的组件使用,不能在其他组件使用
    
    13、全局共享的自定义指令需要在main.js  通过“vue.directive()”进行声明
        像定义全局过滤器一样,以对象形式写两个函数方法
        Vue.directive('c',{
          binding(el,binding){
          el.style.color=binding.value
          },
            update(){
          el.style.color=binding.value
          }
    })
    
    14、如果逻辑一样,可以以函数形式写代码
        Vue.directive('c',function(el,binding){
        el.style.color=binding.value
    
    })
    
    
    main.js
    // 引入残缺版的vue,残缺版的vue不能自己渲染页面
    // 只有完整版的vue能够渲染,
    // vue由两部分组成:核心(生命周期、路由)+模板解析器
    // 节省空间,残缺版去掉了模板解析器,通过render函数
    // 去渲染页面
    import Vue from 'vue'
    import App from './App.vue'
    
    Vue.config.productionTip = false
    
    Vue.directive('c',function(el,binding){
    el.style.color=binding.value
    
    })
    
    
    new Vue({
      el:"#app",
     render:h=> h(App)
    
    })
    // .$mount('#app')
    
    
    bind对象和它的缺点
    
      
      
      
    
    update的优点
    
    
    
    
    

    21、路由

    21-1、理解路由
    1、路由就是对应关系,route
    
    2、路由器:router
    
    3、路由就是一组key-value的对应关系,多个路由需要经过路由器的管理
    
    4、路由就是为了实现单页面应用。
    
    5、项目由导航区和展示区组成
    
    1、路由指的就是Hash地址与组件之间的关系
    
    2、#号代表锚链接,不会导致页面的刷新,会导致历史记录的变化
    
    3、普通的超链接: 是跳转到不同的页面
    
       锚点: 可以在同一个页面中不同的位置间跳转
       
    4、建立锚点目标,只需要给目标元素增加 id 或者 name 即可
    
       锚的名称可以是任何你喜欢的名字
    
       可以使用 id 属性来替代 name 属性,命名锚同样有效,推荐使用 id
       
    5、#往后都叫做hash地址,   
    
    锚链接
    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>#锚链接title>
        <style>
            div{
                height: 800px;
            }
        #d1{
            background-color:red ;
        }
        #d2{
            background-color:rgb(26, 224, 108) ;
        }
        #d3{
            background-color:rgb(22, 56, 230) ;
        }
        #d4{
            background-color:rgb(231, 65, 143) ;
        }
        nav{
            position: fixed;
            top: 0;
            left:0;
        }
    
        style>
    head>
    <body>
      <nav>
        <a href="#d1">d1a>
        <a href="#d2">d2a>
        <a href="#d3">d3a>
        <a href="#d4">d4a>
      nav> 
      <div id="d1">div> 
      <div id="d2">div> 
      <div id="d3">div> 
      <div id="d4">div> 
    body>
    html>
    
    21-2、路由的工作方式
    1、点击页面上的路由连接后,url地址栏上的hash值发生改变,前端路由监听到了hash地址的变化,然后把当前hash地址对应的组件渲染到浏览器中
    
    2、在html页面中对应关系: a#d1  <->  div#d1
    
    3、在vue中路由:path:"#/d1",compoment:#d1
    
    
    21-3、简单的路由实现
    1、window.onhashchange监听页面的hash值变化
    
    2、location.hash.substring(2)截取本地的hash值的字符串2位后的字符串
    
    3、使用动态组件决定显示那个页面,is属性绑定一个动态组件,切换组件
    
    
    
    
    
    
    21-4、vue-router的使用
    1202227日以后,vue-router的默认版本,为4版本,4版本适用于vue3
      3版本的vue-router适用2版本的vue。我们直接安装vue-router就会报错,   出现。
       Found:vue @2.。。。
       peer vue@“^3.0..
       所以一定要安装正确版本
       
    2、cmd安装vue--router的版本,指定3版本
      npm i vue-router@3
      
    3、vue-router是一个插件库,需要use。
      import VueRouter from 'vue-router'
       Vue.use(VueRouter)
    
    4、创建一个router文件夹,用于创建整个应用的路由器,创建一个index.js
      文件。
      1)、引入路由vue-router
       import  VueRouter from 'vur-router'
      2)、创建路由器
       const router=new VueRouter({ }) 
      3)、配置路径routes,path,表示显示的url路径的hash地址,component     表示那个hash地址显示对应的组件 
        // 创建一个路由器
      const router=new VueRouter({
        routes: [
            {
                path:'/hello',
                component:Hello
            }
        ]
    }) 
       4)、因为配置的component是组件上,所以我们还需要引入组件
       import Login from '@/components/Login.vue'
       import Regist from '@/components/Regist.vue'
       
       5)、暴露这个路由器
        export default router
    
       6)、简写
       export default new VueRouter({
        routes: [
            {
                path:'/hello',
                component:Hello
            }
        ]
    }) 
       
       7)、在main.js里面引入路由器
         import  router from '@/router'
      
       8)、使用router-link标签跳转路径,这个标签实际上就是a标签
           <router-link to="/login">Login</router-link>
     
       9)、这个时候页面没有展示出来。需要向slot插槽一样,给要显示组件的地方需要用到 router-view占位。组件一个router-view标签,表示router显示的页面展示在这个位置
           <router-view></router-view>
       
    10、这些定义了hash路径的组件都叫做路由组件
    
    

    router的index.html

    // 用于创建整个应用的路由器
    import  VueRouter from 'vue-router'
    // 引入组件
    import Login from '@/components/Login.vue'
    import Regist from '@/components/Regist.vue'
    
    // 创建一个路由器
    export default new VueRouter({
        routes: [
            {
                path:'/login',
                component:Login
            },
            {
                path:'/regist',
                component:Regist
            }
        ]
       
    
    }) 
    
    

    main.js

    // 引入残缺版的vue,残缺版的vue不能自己渲染页面
    // 只有完整版的vue能够渲染,
    // vue由两部分组成:核心(生命周期、路由)+模板解析器
    // 节省空间,残缺版去掉了模板解析器,通过render函数
    // 去渲染页面
    import Vue from 'vue'
    import App from './App.vue'
    
    import VueRouter from 'vue-router'
    import  router from '@/router'
    
    Vue.use(VueRouter)
    
    Vue.config.productionTip = false
    
    
    
    new Vue({
      el:"#app",
      router:router,
      render:h=> h(App)
    
    })
    // .$mount('#app')
    
    

    App引入router

    
    
    
    
    
    21-5、路由注意点
    1、配置了hash路径的组件都叫做路由组件
    
    2、这些路由组件一般放在pages文件夹下面。
    
    3、$route:这个组件的路由信息,每个路由组件都有。 route是单个路由,存放           当前路径信息,携带的参数
    
    4、$router:整个应用的路由器。只有一个路由器。 管理整个路由系统,里面保            存所有的路径信息,能够实现路由的跳转
    
    5、通过切换。“隐藏”了的路由组件,默认是被销毁掉的,需要的时候再去挂载
    
    
    21-6、嵌套路由
    1、一级路由,定义在routes对象中,是routes对象的属性,被定义为一级路      由。
    
    2、多级路由是一级路由的孩子。使用routes的children属性定义,children是一个数组,里面可以配置多个对象,对象的写法和以及路由是一样的。是被定义在一级路由为代表的路由组件里面的路由组件。children里面不用添加 /
            {
                path:'/regist',
                component:Regist,
                children:[
                    {
                        path:'home',
                        component:Home
                    }
                ]
            },
    
    3、使用的时候,记得to属性加上完整路由。
       <router-link to="/regist/home">Home组件</router-link>
    
    21-7、路由传参
    1、路由跳转的时候可以传递参数,而跳转到的那个路由组件可以接收到值传递的这个参数值。
      <router-link to="/regist/home/hello?id=01"> {{ item.name }}</router-link>
     
    2、每个路由组件都有一个this.$route对象,有关于这个路由组件的很多多信息。
        <li>学生学号{{ $route.query.id}}</li>
    
    3、动态展示传递过去的参数,使用属性绑定v-bind绑定to属性,让字符串变成动态表达式,然后使用模板语法用 ` `括起来,把name属性=对象的id属性,使用${}。让这句话变成模板字符串。这是跳转路由携带query参数的to的字符串写法
    
    <router-link
    
    :to="`/regist/home/hello?id=${item.id}&name=${item.name}`"
    > 
         {{ item.name }}
        
        </router-link>
                        
    4、跳转路由并携带query参数to的对象写法,path代表路径,表示你跳转的路由组件的地址,还有query参数,query是一个对象,里面装的就是要携带的参数,这样写的好处是简单明了
          <router-link :to="{
                            path:'/regist/home/hello',
                            query:{
                                id:item.id,
                                name:item.name
                            }
                         }">
                        {{ item.name  }}
                        </router-link>
    
    
    21-8、命名路由
    1、name是什么呢?name 是配置路由时给 path 取的别名,方便使用。但要注意的是 “地址栏显示的路径始终是 path 的值”.可以简化代码,就在routes设置里面添加一个name属性。
          {
                name:'login',
                path:'/login',
                component:Login,
                
            
            },
                
    2、这个name属性可以简化代码。比如说路径跳转的时候我们使用path进行路径跳转。
      //在routes设置跳转的 路由的name属性
          {
                name:'login',
                path:'/login',
                component:Login,
                
            
            },
         //路由跳转:通过name属性跳转
                 <router-link :to="{
                            name:'hello',
                            query:{
                                id:item.id,
                                name:item.name
                            }
                         }">
                        {{ item.name  }}
                        </router-link>
    
                
    
    21-9、params参数
    字符串写法
    1、在跳转前的组件通过to属性使用/传递参数,但是要在路径的path属性里面去声明这是接收参数。通过占位符来声明,跳转到的路由组件接收参数的写法也不一样。
         //传递固定格式的数据的写法
                        <router-link :to="`/regist/home/hello/007/王老五`">
                            {{ item.name}}
                        </router-link>
    
         //传递动态数据的写法
           
                        <router-link :to="`/regist/home/hello/${item.id}/${item.name}`">
                            {{ item.name}}
                        </router-link>
    
    2、在路由组件的路由设置里面通过占位符声明接收的参数。这些数据就会放在params对象里面。
        path:'hello/:id/:name',
         
    3、路由组件接收的参数的方式,通过params对象去接收:
             <li>学生学号{{ $route.params.id}}</li>  
    
    对象写法
      必须把path换成name就可以了。不能使用path,
      然后query对象的参数换成params对象设置传递的数据参数
      
      
    4、解决路由组件接收参数写死的情况,路由的props配置:,
      在路由里面设置,使用rpops参数去接收,
        
      1//第一种写法,值为对象,
       {
                                name:'hello',
                                path:'hello/:id/:name',
                               component:Hello,
       //    props的第一种写法,值为对象,该对象
         // 所有key-value都以props形式传递给这个hello组件
                               props:{a:1,str:"小红"}
                            }
      路由组件通过props接收这个两个变量的值
         props:['a','str'],
      组件可以直接使用这两个数据,但是,这是写死的数据,不推荐使用
            <li>{{ a}}</li>
            <li>{{ str }}</li>
      
    
       2//第二种写法,值为布尔值,
        // props的第二种写法,值为布尔值,若布尔值为真
        // 就会把该路由收到的所有的params参数以props
        // 的形式转给该路由组件
           {
             name:'hello',
             path:'hello/:id/:name',
             component:Hello,              
           // props的第二种写法,值为布尔值,若布尔值为真
           // 就会把该路由收到的所有的params参数以props
            / 的形式转给该路由组件
             props:true
                        }  
       
       引用路由组件的字符串写法
      <router-link :to="`/regist/home/hello/${item.id}/${item.name}`">
             {{ item.name}}
       </router-link> 
        路由组件通过props接收这个两个变量的值
           props:['id','name'],
        组件可以直接使用这两个数据,但是,这是写死的数据,不推荐使用
            <li>学生学号{{ id}}</li>
            <li>学生姓名{{ name}}</li>
    
        对象写法
          <!-- 6、路由跳转携带params 参数,引用路由的组件对象写法写法-->
            
                   <router-link :to="{
                    name:'hello',
                    params:{
                        id:item.id,
                        name:item.name
                    }
                   }">
                            {{ item.name}}
                        </router-link>
       
       4)如果把路径删了,想转成query参数。通过props接收,不能使用props接收的数据,会告诉你属性未定义,只能通过query对象使用数据
      引用路由的组件设置跳转路由
         <!-- 7、跳转路由由query 接收props传递的数据 -->
                        <router-link :to="{
                         name:'hello',
                         query:{
                            id:item.id,
                            name:item.name
                         }
                       
                        }"> {{ item.name }}</router-link>
         路由组件接收传递的参数的写法
            <li>学生学号{{ $route.query.id}}</li>
            <li>学生姓名{{ $route.query.name}}</li>
       路由设置
            {
                name:'hello',
               // path:'hello/:id/:name',
                path:'hello',
                component:Hello,
              // 如果把路径删了,想转成query参数。通过props接收。
              props:true
       }
       
        5)props的第三种方法:值为函数。
             // props的第三种写法:值为函数,
                   //值为函数的第一种写法
             // props(){
             //  这是写死的用法。这个props传递的数据既不在params
              //里面,也不在query里面
              //   return {id:11,name:"小兰"}
              /  }
                 
        
         //值为函数的第二种写法:
         // 传入route对象,就可以使用query里面的参数传递数据 
          props($route){
           // 这是写死的用法。这个props传递的数据既不在params
           //    里面,也不再query里面
           
          return {
              id:$route.query.id,
              name:$route.query.name}
      }
    
        //值为函数的第三种写法:
           // 解构query对象,使用里面的数据
            props({query}){
           return {id:query.id,name:query.name}
         }
    
           //值为函数的第四种写法:
            // 再解构赋值
             props({query:{id,name}}){
                return {id,name}
              }
    
    5、props的作用:让路由组件更方便的收到参数,既适用于params也适用于  query
    
    
    21-10、params和query的不同
      在Vue路由中,query和params都是用于向路由添加附加信息的方式。query通常用于传递查询字符串,而params则用于传递路由参数。query通过URL中的“?”传递附加信息,而params则在路由路径中传递,例如“/users/:id”。params可以使用$router.push()来更改,而query则使用$router.replace()。查询参数和路由参数在Vue的$route对象中都可以使用,但是路由参数更适用于表示唯一标识符,例如用户ID,而查询参数更适合用于分页或搜索过滤器等用途
    
    21-11、路由跳转的两种导航方式
    1、声明式导航,
            在浏览器中,点击链接实现导航的方式,叫做声明式导航。
    
            例如:普通网页中点击a链接,vue项目中点击都属于声明式导航
            
    2、 编程式导航
          在浏览器中,调用API方法实现导航的方式,叫做编程式导航。
    
          例如:普通网页中调用location.href 跳转到新页面的方式,都属于编程式导航
    
    作用:不借助实现路由跳转,让路由跳转更加灵活      
    
    
       
    
    21-12、router-link的replace属性
    1、路径以push模式增加为历史记录,一条条路径重叠,不破坏任何一条路径。最新的页面在最上面
    
    2、replace属性直接替换当前路径页面,不会生成页面记录,写法,直接添加replace属性,在router-link里面。
       
    <router-link 
    
        replace
        
        to="/regist/home">Home组件
    
    </router-link>
    
    3、总结:replace属性的作用
       1)、作用:控制路由跳转时操作浏览器历史记录的模式
       
       2)、浏览器的历史记录有两种写入方式,分别为push和replace,push是追加历史记录,replace是替换当前记录,路由默认为push
       
       3)、开启replace模式的方法:在router-link里面添加replace属性。
    
    21-13、编程式导航
    1、在浏览器中,调用API方法实现导航的方式,叫做编程式导航。
    
          例如:普通网页中调用location.href 跳转到新页面的方式,都属于编程式导航
    
    2、使用路由器:$router的api方法跳转
       pushShow(m){
                this.$router.push({
                        name:'hello',
                         query:{
                            id:m.id,
                            name:m.name
                         }
    
                })
    
            },
            replaceShow(m){
                this.$router.replace({
                        name:'hello',
                         query:{
                            id:m.id,
                            name:m.name
                         }
    
                })
    
            }
    3、使用路由器方法的前进后退:
          this.$router.back
          this.$router.forward
    
    4、编程式导航的作用:不借助router-link实现路由跳转,让路由跳转更灵活
    
    
    21-14、缓存路由组件
    1、通过keep-alive:让不展示的组件保持挂载,不被销毁
    
    2、是在路由router-link里面指定,include属性指定哪个组件被挂载
    
    3、缓存多个组件的写法
      :include="['组件1','组件2']"
    
    21-15、路由组件相关的生命周期
    1、activated:激活时触发
    
    2、deactivated:失活时触发
    
    3、路由组件所独有的两个钩子,用于捕获路由组件的激活状态
    
    21-16、全局路由守卫
    1、路由守卫的作用:对路由进行权限控制,分类:全局守卫、独享守卫、组件内守卫。如果想实现登录注册后才能看见网站首页,就需要添加路由守卫
    
    2、第一步就是在路由组件里面选择不直接暴露router。而是直接定义一个router对象,
    
    const router=new VueRouter({
    routes:[
    {
     
    }
    ]
    })
    
    //全局前置路由守卫,路由切换之前会调用
    //初始化的时候调用
    router.BeforeEach((to,from.next)=>{
    
    })
    
    3、to和from是去的路由组件和前一个路由组件,里面是路由组件的相关信息。next()表示放行,如果不放行,是不会执行到下一步,
    
    4、所以前置路由守卫一般是用来判断,是否登录注册过,才可以跳转页面,然后可以路由跳转到其他页面,to.name也可以
       if(to.path=='/login' || to.path =='/regist'){
           if(这里和数据库的会员数据做比对,一致的话就可以放行){
               next()
           }
           else
               {
                   console.log("不能成功登录")
               }
           
       }
    
    5、meta:提供容器配置特殊的数据。称作路由原信息,配置程序员自己想配置的信息,可以用来作为验证路由守卫的信息。也可以用来做网页的title信息。
      const router=new VueRouter({
    routes:[
    {
        name:'hello',
        path:'/hello',
        component:Hello,
        meta:{isNext:true}
     
    }
    ]
    })
    
    6、使用meta信息判定权限:
    //判断是否需要鉴权
         if(to.meta.isNext){
           if(这里和数据库的会员数据做比对,一致的话就可以放行){
               next()
                 
           }
           else
               {
                   console.log("不能成功登录")
               }
           
       }
    
    7、全局后置路由守卫:初始化之后调用,每次切换之后调用,没有next,不需要放行。
        router.afterEach((to,from)=>{
            document.title=to.meta.title  || '网站'
        })
    
    21-17、独享路由守卫
    1、某一个路由单独想用的守卫。
    
    2、想设置独享路由守卫,在设置路由里面设置beforeEnter。表示进入这个路由之前。进行规则的对比,只对该路由组件做测试。
       routes:[
    {
        name:'hello',
        path:'/hello',
        component:Hello,
        meta:{isNext:true},
        beforeEnter((to,from,next)=>{
       
       })
     
    }
    ]
    
    3、独享守卫只有前置没有后置,可以喝全局后置守卫搭配使用。
    
    21-18、组件内路由守卫
    1、beforeRouteEnter,路由组件使用的函数,通过路由规则,进入该组件时被调用。
     beforeRouteEnter(to,from.next){
     
     }
     
    2、beforeRouteleave,路由组件使用的函数,通过路由规则,离开该组件时被调用。
         beforeRouteleave(to,from.next){
     
     }
    
    21-19、history模式与hash模式
    1、hash值最大的特点:hash值不会因为http请求作为路径数据发给服务器,是程序员自己设置的路径
    
    2、可以通过在路由器里面设置mode属性,选择路由是history模式还是hash模式,默认是hash模式
      const router=new VueRouter({
       mode:'history',
       routes:[
       
       ]
      })
      
    3、开启history模式后不会再有hash值。需要新开页签
    
    4、hash兼容性好,history兼容性较差。
    
    5、npm的中间件:connect-history-api-fallback专门解决history模式404的问题。
    
    6、总结;
      hash模式:
        1、地址中带着#号,不美观
        2、如果以后将地址通过第三方手机app分享,如果app校验严格,则地址会被标记不合法
        3、兼容性较好
        
      history模式:
         1、地址干净、美观
         2、兼容性和hash模式相比略差
         3、应用部署上线时需要后端人员支持,解决刷新页面服务器404问题
    
    21-20、路由重定向
    暂时省略
    
    21-21、路由懒加载
    暂时省略
    

    22、minxin:混入

    22-1-1、什么是混入
    1、mixins(混入),官方的描述是一种分发 Vue 组件中可复用功能的非常灵活的方式 mixins 是一个 js 对象,它可以包含我们组件中 script 项中的任意功能选项,如:data、components、methods、created、computed 等等。我们只要将公用的功能以对象的方式传入 mixins 选项中,当组件使用 mixins 对象时所有 mixins 对象的选项都将被混入该组件本身的选项中来,这样就可以提高代码的重用性,并易于后期的代码维护
    
    22-1-2、怎么使用mixin
    1、当我们存在多个组件中的数据或者功能很相近时,我们就可以利用 mixins 将公共部分提取出来,通过 mixins 封装函数,组件调用他们是不会改变函数作用域外部的。
    2、一样的方法我们把它提取出来放在一个公共的地方
    
    22-1-3、如何创建mixin
    1、在 src 目录下创建一个 mixins 文件夹,在文件夹下新建一个myMixins,js 文件。 因为 mixins 是一个 js 对象,所以应该以对象的形式  来定义 myMixins,在对象中可以和vue 组件一样来定义 data、components、methods、created、computed   等属性,  并通过 export 导出该对象。export表示分别暴露,如果需要在组件里面使用该混合,需要在该组件引入,因为是分别暴露,所以,需要以对象的形式暴露:
          import {mixin} from '../mixin'
       然后,所以我们使用mixins配置项去接收,因为有多个的mixin,所以数组形式接收,只有一个混合也这样写
           mixins:[mixin]
    2、组件有的东西以组件为主,组件没有的以混合为主
    3、生命周期mountend都会实现
    4、功能:就是可以把多个组件共用的配置提取成一个混入对象
    
    22-2、案例
    export  const mixin={
        methods:{
            fn(){
              
                this.n++
            }
        }
    }
    
    
    <template>
      <div>
        {{ n }}
    <button @click="fn">按我+1</button>
    
      </div>
    </template>
    
    <script>
    import {mixin} from '../mixin'
    export default {
        data(){
            return{
                n:2
    
            }
        },
        mixins:[mixin]
       
    
    }
    </script>
    
    
    
    22-3、定义全局混合
    1、在main.js里面引入混合,然后使用Vue.mixin()就可以使用该混合里面的方法了
      import {mix}  from './mixin'
      Vue.mixin(mix)
    

    23、过渡与动画

    1、过渡与动画的作用:在插入或移除DOM元素的时候,在核实的时候给元素添加样式类名
    
    2、有进入的样式和离开的样式
    
    3、进入
       v-enter:进入的起点
       v-enter-active:进入过程中
       v-enter-to:进入的终点
    
    4、离开
       v-leave:离开的起点
       v-leave-active:离开过程中
       v-leve-to:离开的终点
       
    5、进入的终点就是离开的起点
    
    6、使用transtion包裹想要过渡的元素,
    
    23-1、动画
    23-2-1、Vue动画的理解
    1、设置来回切换的效果,vue用transtion包裹有动画效果的元素,设置进入的时候的的类名:v-enter-active,设置离开的时候的类名:v-leave-active。
    
    2、这个transtion还可以起名字,
        <transition name="tr">
        <nav v-show="flag">动画效果</nav>
    
      </transition>
    
    3、如果给transtion起了名字,那么,v-enter-active就改成 transtion的名字-enter-active
    
    4、设置一开始就是动画效果,就给transtion设置一个appear属性,设置属性值为true,但是要通过v-bind进行绑定。不然的话是一个布尔值
           <transition name="tr" :appear="true">
          <nav v-show="flag">动画效果</nav>
      
        </transition>
     
    5、transtion在vue解析的时候没有被解析,是给vue 设置动画的,动态给元素添加样式的动画效果
    
    
    
    
    
    
    
    
    23-2、过渡
    1、vue提供了transtion的封装插件,在下列情形中,可以给任何元素和组件添加enter/leave过渡
      1、v-if
      2、v-show
      3、动态组件
      4、组件根节点
    
    过渡的类名
    1、v-enter:进入的起点,在外边的盒子以左边坐标为开始,向右从-100%的位置开始
    
    2、v-enter-to:进入的终点,在里边的盒子以左边的坐标未开始,向左从0%的位置转
    
    3、v-leave:离开的起点,0%的位置开始转移
    
    4、v-leave-to:离开的终点,转移到-100%的位置
    
    5、给元素设置transtion。同样位置的一样的类名设置可以放在一起
    
    
      
      
      
      
    
    22-2-1、多个元素过渡
    1、 can only be used on a single element. Use <transition-group> for lists.
       transtion只能有一个元素,多个元素可以使用transtio-group
    
    2、transtion-group的元素必须有唯一的key值
     
      <transition-group name="tr" appear>
        <nav v-if="flag" key="one">1</nav>
        <nav v-if="flag" key="two">2</nav>
      </transition-group>
    
    22-3、动画库(使用第三方库写动画样式)
    1、搜素npm.js官网,https://www.npmjs.com/
    
    2、在官网里面搜索animate.css,点击第一个
       https://www.npmjs.com/package/animate.css
       
    3、选择animate.style
      https://animate.style/
      
    4、根据animate上面的步骤进行使用:
       1、安装,停止该项目,安装animate
       2、引入样式库
         import 'animate.css'
       3、复制粘贴类名,放在name属性上
         animate__animated animate__bounce
       4、给这个transtion指定进入和离开的类名,复制类名 字符串里面是自己喜欢的动画效果
      
      进入的类名:enter-active-class=””
      
       离开的类名:leave-active-class=””
       
        
        
      
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1nGHkSMl-1686141820666)(C:\Users\Direct\Desktop\常用前端框架及工具\拓展学习资料\7-animate使用.PNG)]

    23、Vue原理

    23-1、MVVM
    1、Vue坐着参考mvvm模型,m(model)代表模型,v(view)代表视图,模板,vm,视图模型,vue实例对象
    
    
    23-2、数据代理
    1、是否被枚举指的是是否可以被遍历出来
    
    2、数据代理:通过一个对象代理对另一个对象中属性的操作
    
    3、重点:Object.defineProperty,
    

    24、配置代理

    1、跨域,也就是违背了同源策略:主机名、协议名、端口号必须一致
    
    2、解决跨域的方法
          1.cors,后端人员添加特殊的响应头,
          2、jsonp,通过script标签,前端后端一起设置,只能设置get方法
          3、代理服务器,服务器和服务器之间传递数据不用ajax请求,使用的是http协议,而代理服务器的端口号和客户端的端口号这些是一致的,满足同源策略
    服务器之间不受同源策略的影响
    
    3、代理服务器的几种方式:
         1、nginx
         2、借助vue-cli
         
    4、vue脚手架设置代理服务器的方式,在vue.config.js里面设置
        1、打开vuejs的官网,选择vue2文档,点击配置参考,选择devServer。procy,
        2、按照参考文档设置
        3、lintOnSave:false  //关闭语法检查
        
        //举例
        module.exports = {
        devServer: {
        //这里是告诉代理服务器等会在哪个服务器请求数据,在这里就开启了一个
        //代理服务器,所以设置的是请求数据的服务器端口
          proxy: 'http://localhost:4000'
        }
      }
      
        4、在axios请求数据的时候改变端口号,只改变自己的端口号,不改变请求路径。然后重启项目,比如服务器端口号是4000,但我们设置了代理服务器,axios请求的路径本来是4000,但我们改成本机端口号80880
        axios.get('http://localhost:4000')
       改:axios.get('http://localhost:8080')
     
     5、两个小问题:
          1、只能配置一个代理服务器
          2、没办法控制走不走代理,因为如果文件的public有路径文件,会优先获取public里面的。
          
    6、解决以上两个问题的方法,看官网
      第二种方法
     module.exports = {
      devServer: {
        proxy: {
            //第一个代理
            ///api叫做请求前缀,如果请求前缀是api就走代理服务器
          '/api': {
              //target是服务器的路径
            target: '',
              //用于支持websocket:
            ws: true,
              //true表示隐瞒自己的端口号,
              //用于控制请求头中的host值
            changeOrigin: true
          },
            //第二个代理
          '/foo': {
            target: ''
          }
        }
      }
    }
    
     注意:在这里因为设置了请求前缀,我们的axios也要作出相应改变,在端口号的后面添加请求前缀,其他的不会改变
      axios.get('http://localhost:8080/api')
     
    
      但是因为axios请求的路径会完整的带给服务器去请求数据,所以我们要去设置一个配置。
      //重写路径,它是一个对象格式,里面是key、value形式,表示所有以api开头的路径将被替换为空字符串
      pathRewrite:{'/api':''}
    
    7、第二种方法的优点:可以配置多个代理,且可以灵活的控制请求是否走代理
                 缺点:配置稍微繁琐,请求资源时必须添加前缀
    

    25、axios

    25-1、项目中使用
    1、在vue里面使用axios需要先安装axios,
    
      npm   i axios  -S
    
    2、在组件中引入
    
      import  axios from  'axios'
    
    3、调用方法
    
    ​     axios.get()
    
    25-2、axios拦截器
    暂时省略
    

    26、nanoid

    1、使用nanoid可以给数据生成id,
    
    2、
      先引入
      import {nanoid} from 'nanoid'
      
      后使用,直接使用
      this.id=nanoid()
    
    

    27、Vue UI组件库

    27-1、移动端组件库
    1、Vant
    2、Cube  UI
    3、Mint  UI
    
    27-2、PC端常用UI组件库
    1、element  UI
    2、IView  UI
    

    你可能感兴趣的:(vue.js,学习,javascript)