vue基础综合

基于脚手架创建项目:

需要安装准备好的底层环境:node环境,vue-cli脚手架

  1. 安装node:地址 node -v查看版本

  2. 安装vue-cli脚手架:

    ​ npm install -g @vue/cli 全局安装(不能创建vue 2.x项目)

    ​ npm install -g @vue/cli-init (作为桥接,创建vue 2.x项目)

  3. 创建项目:vue create 【项目名】

  4. 初始化:npm install

    ​ 下载package.js里面的包和插件等,放置在node_modules中

  5. 开启服务:npm run serve

安装的库

npm install 指定的插件@4.1.0 --save

  1. 项目中安装生产模式的router:npm install vue-router --save
  2. 安装axios:npm install axios
  3. 安装生产模式的vuex:npm install vuex --save
  4. 安装less和less-loader:npm install less less-loader@7 --save
  5. 安装 npm install --save js-cookie
  6. 安装虚拟接口调试:npm install mockjs -D
  7. 安装UI库:

报错:Syntax Error: TypeError: this.getOptions is not a function

解决方案:less-loader 版本太高需要降低到 7版本

报错跨域问题:

解决:需要 import ‘./mock’,即将拦截的文件以及数据统一放到main.js中

创建Mock数据接口(假数据):

一、基础介绍

1.Vue实例选项

el

作用:指定、设置,当前Vue实例所管理的视图。

  1. 值可以是id
  2. 值可以是其他选择器
  3. 值可以为DOM元素

注意:不能让el直接管理html或者body 报错!! mount->挂载

data

作用:指定、设置 当前Vue实例所用的数据。

  1. 值可以是一个对象{}、数组[]、字符串”“、数字:1
  2. data中的数据,可以通过Vue实例对象.属性名 去访问数据
  3. 访问数据 可以通过app.massge访问

特点:响应式数据(当数据变化时,视图中的数据会自动发生变化)

methos

作用:放置自定义函数。

  1. 可以在视图中通过{{}}调用方法
  2. 可以通过app对象.方法名去调用方法(app.data.paly())
  3. 方法中的this指的是当前的Vue实例对,即app

注意:不推荐些箭头函数,因为箭头函数this指向的不是实例本身,即app本身

watch

作用:当被监测的数据发生变化时 会触发方法,要进行异步操作的时候。

  1. 被监测的数据名:函数()
  2. msg:function (newVal,oldVal) {}

2.Vue专业术语解析

  • 插值表达式作用:会将绑定的数据实时的显示出来
    • 通过任何方式修改所绑定的数据,所显示的数据都会被实时替换{{js表达式、三目预算符、方法调用等}}
    • 不能写var a = 10;分支语句 循环语句
  • 指令:是带有v-前缀的特殊特性,增强html功能
    • 所有的指令都在开始标签位置
    • 每个指令都是为了取代DOM操作

3.关于ES6相关语法问题:

展开运算符的结构解析
<let a = [1,2,3];
let b = [0, ...a, 4]; 
b返回的数组为 [0,1,2,3,4],得出结论:展开运算符可以直接在数组内直接使用,同时可以生成一个新数组。

let obj = { a: 1, b: 2 };
let obj2 = { ...obj, c: 3 }; 
// { a:1, b:2, c:3 }
let obj3 = { ...obj, a: 3 }; // { a:3, b:2 }>

注意:展开运算符不能直接使用:
:console.log(…person)//报错,展开运算符不能展开对象,需要使用{}进行包裹:因为console.log输出的是运算后的结果,即为表达式。

ES6中模板字符串的使用:

使用场景:字符串中需要包裹变量的时候

你输入的用户名是:${username.value},你输入的密码是${password.value}

高阶函数:

简介:一个函数复合下面两个规范中的任何一个,那么函数就是高阶函数。
若A函数,接收的参数是一个函数,那么A就可以称之为高阶函数。
若A函数,调用的返回值依然是一个函数,那么A就可以称之为高阶函数。

常见的高阶函数:Promise、setTimeout
函数的柯里化:通过函数调用继续返回函数的方式,实现多次接受参数最后统一处理的函数编码形式

结构赋值语句/连续解构

从数组第一个对象元素中提取某个属性,比如:err 对象中包含一个 errors 数组,errors 数组每一个对象都包含一个 msg 属性

err = {
  errors: [
    {
      msg: 'this is a message'
    }
  ]
}

快速的提取方法为:

const [{ msg }] = err.errors
或
const [ obj ] = err.errors
const { msg } = obj

如果不用解构写法为:

const msg = err.errors[0].msg
模块引入和暴露:
//模块引入
//方式一:
import m1 from './main.js'

//解构赋值形式
import {m1,m2} from './main.js'
//取别名的方式
import {m1 as guigu} from './main.js'


//模块导出
export let school = 'guigu'

export {
	school,
    school1
}

//默认导出
export default{
    school,
    school1
}

二、系统指令:

​ 具体方式方法:见vue.js官网中的学习API中

1.<v-text和v-html>:动态文本

v-taxt:更新标签中的内容

v-text和插值表达式的区别:

  • v-text更新整个标签中的内容
  • 插值表达式{{}}:更新标签中局部的内容

v-html:更新标签中的内容/标签(也可以替换标签中的全部内容)

注意事项:

  • 可以渲染内容中的HTML标签
  • 尽量避免使用,容易造成攻击

2. <指令v-on>:绑定事件监听器

作用:绑定DOM事件监听器,并在时间被出发时执行一些JavaScript。

语法:v-on 简写为@

@事件名.修饰符 = ”methods中的方法名“

常用修饰符:事件修饰符,once和prevevt等。

注意:$event用来传递事件对象。

3.<指令v-for>:渲染内容

列表渲染

语法:

v-for="item in 数组"  
v-for="(item,index) in 数组"
// item指的时数据中每个元素的值,index指的是每个数字所在数组的索引、下标

对象渲染

语法

v-for="(item,index) in 对象"

注意事项:vue建议我们给每个循环遍历的标签li 加key属性,key属性值特点 要求是唯一值,key值为下标、索引,value值,key名

作用:vue渲染页面是,根据key的标识找到每一个元素,效率更高,关系到虚拟DOM的对比。

5.<指令v-bind>:动态绑定数据

作用:动态绑定标签的任何属性,例如input 中的 value属性

场景:当标签属性值是不确定的是可以修改的

语法:v-bind:要绑定的属性名=“data中的数据”

简写:去掉v-bind,即:,例如:src/:id

//绑定class-对象:
<p v-bind:class="{active:a,left:b}">内容</p>           

data:{
    a:ture,
    b:false
}
//解析:通过动态来绑定class的类名

           
//绑定class-数组:
<p :class="[left,active]">内容</p>
data:{
    left:"a",
    active:"b",
}
//解析:通过数组的方式,同时绑定多个类名。        
//绑定style-对象
<p :style="{fontSize:a,color:b}">1236</p>
data:{
    a:"25px",
    b:"#f5f5f5",
}

//绑定style-数组
//语法:数组语法,数组里面包含的是对象
<p :style="[a,b]">1236</p>
data:{
     a:{
         'color':"#d00c0c"
     },
     b:{
         'fontSize':'25px',
     }
 } 

6.<指令v-model>:数据的双向绑定

特点:双向数据绑定,数据发生变化可以更新到界面,通过界面可以更改数据,当在视图修改数据值时,data中的数据也会相应发生变化。

注意事项:v-model会忽略所有表单元素的value、checked、selected特性的初始值而总是将Vue实例的数据作为数据来源,应该在data选项中声明初始值。

表单元素的应用

  • 多行文本输入框:textarea标签内容是无效的
  • 复选框:
    • 一个复选框v-model=“布尔值”
    • 多个复选框v-model=“同一个数组”
  • 单选按钮radio:
    • 多个单选按钮绑定v-model=“同一个数据”
  • 下拉框select+option:
    • 显示默认项v-model=“select”和默认option的value值一致
    • select值是选中对应value值

数据双向绑定实现的原理

1.动态绑定数据,当data里面数据变化时,页面上的数据也会发生变化。

2.通过监听事件@input来触发事件,然后在事件中修改绑定的数据,即可实现数据的伪双向绑定。

场景:实现一个自定义v-mode的形式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Boi8gdwf-1619607904201)(img\1603104634638.png)]

7.<v-if 和 v-show>:动态显示

v-if

简介:根据表达式的值的 truthiness 来有条件地渲染元素。在切换时元素及它的数据绑定 / 组件被销毁并重建。

v-show:

简介:根据表达式之真假值,切换元素的 display CSS property。在切换的时候,不会被销毁

当条件变化时该指令触发过渡效果。

keep-alive :

简介:等价于v-show,复杂的组件使用keepalive 简单的可以使用v-show来提高性能

场景:缓存组件,频繁切换,不需要重复渲染的情况,vue常用性能优化方案之一

三、过滤器详解(filters)

简介:过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 (后者从 2.1.0+ 开始支持)。

语法

<p>处理后:{{msg | toUpper(200)} | toLower}</p>

//js
filters: {
  toUpper(value,other) {
	return value.toUpper()
  },
  toLower(value){
	return value.toLowerCase()
  }
}

解析

1)传参数:

  • value参数:是msg,用来处理。
  • other参数:模板p给予的数据

2)串联:

  • toLower 处理的是 toUpper 所return的结果

过滤器的文档分析

​ 1)场景:当数据格式需要处理时(文本格式化)
​ 2)分类:全局和局部(本地)
​ 3)使用位置:{{}}和v-bind:属性=“”

全局过滤器

1)全局过滤器:在newVue之前

  • 步骤
  • 1.在newVue之前Vue.filter('过滤器名字‘,function(){}定义过滤器
  • 2.在过滤器的函数中实现具体的格式处理fuction(v){}
  • 3.在啊视图中使用过滤器{{msg | 过滤器名字}}

四、自定义指令

简介:有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。举个聚焦输入框的例子 。

**应用场景:**自定义指令获取 DOM 元素

语法:使用 directive 实例选项

//html
<input v-focus>

//js
directives: {
  focus: {
    // 指令的定义
    inserted: function (el) {
      el.focus()
    }
  }
}

案例代码:实现一个自定义v-mode的形式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EQOzuQiT-1619607904206)(img\1603104634638.png)]

钩子函数:

简介:一个指令定义对象可以提供如下几个钩子函数 (均为可选)

  • bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。

  • inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。

  • update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前

  • componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。

  • unbind:只调用一次,指令与元素解绑时调用。

钩子函数参数:

  • el:指令所绑定的元素,可以用来直接操作 DOM.

  • binding
    

    :一个对象,包含以下 property:

    • name:指令名,不包括 v- 前缀。
    • value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2
    • oldValue:指令绑定的前一个值,仅在 updatecomponentUpdated 钩子中可用。无论值是否改变都可用。
    • expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"
    • arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"
    • modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }
  • vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。

  • oldVnode:上一个虚拟节点,仅在 updatecomponentUpdated 钩子中可用

ref操作DOM:

场景:在Vue操作dom元素.

生命周期函数:mounted获取要操作的dom元素this.$refs.ref属性值。

$nextTick函数(重要)

场景:vue是异步渲染的框架,react也是,data改变之后,dom不会立刻渲染,$nextTick会在dom渲染之后被触发。

作用:以获取最新dom节点。

案例代码

this.$nextTick(()=>{ //在节点渲染完成后才会调用
    console.log(this.$refs.ulDemo)
})

五、计算属性(computed)

简介:在模板中可以把computed当作data属性来使用,computed是一个对象,每个键是计算属性的值,注意:computed有缓存,data不变则不会重新计算。

使用场景:表达式、当数据A的逻辑很复杂时,把A这个数据卸载计算属性中;或者data中的数据b依赖了数据a

值有两种使用方法:

  • 值是一个函数,必须要有return
  • 值是一个包含get和set的对象

案例代码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-08Lnw8Nf-1619607904208)(img\1602805842921.png)]

解析:get()在数据绑定后,相当于直接赋值给模板中。

set()会在数据改变时触发(数据绑定必须为双向的)

六、监听数据:(watch)

简介:watch是vue内部提供的一个用于侦听功能的更通用的方法,其用来响应数据的变化,通过特定的数据变化驱动一些操作。

基本的书写方式

解析:newValue:监听新的变化值,oldValue上一次的值

watch:{
    message(newValue,oldValue1){
        console.log(newValue,oldValue)
        this.message = newValue
}

监听对象

如果对象内有多个属性,并采用以下写法,则对象内每个属性都会被侦听,每个属性的变化都会执行一次侦听操作

解析:侦听普通变量的变化是使用以上方法,当侦听的某个变量值是对象时则不起作用,这时需要使用deep深度监听。当未设置immediate或者immediate的值为false时,被侦听的变量在页面初次加载时第一次绑定值的时候,并不会执行监听操作;但是当设置了immediate的值为true时,则会立刻执行一次监听操作。

'deepMessage.a.b':{
    handler:'handerFun',
    deep:true,  //是否深度监听
    immediate:true  //监听第一次
}

 deepMessage:{
     handler:'handerFun',
     deep:true,  //是否深度监听
     immediate:true  //监听第一次
}

监听数据,相应多个函数时

lastMessage:[
    {
        handler:'lastFun'
    },
    'lastFun1',
    function(value){
        console.log(value)
    }
]

七、组件基础

1.组件是特殊的Vue实例

  • 可以任意次数的复用
  • 每用一次组件,就会有一个它的新实例被创建
  • 组件中的data要求必须是一个函数,且需要返回一个对象,组件有自己的作用域。
  • template每个组件模块有且只有一个根元素

建议:在实际开发中,尽量可能使用各种第三方组件

2.组件特点

  • 组件体现封装思想(html+css+js)
  • 组件是特殊的vue实例(data、methods等选项)
    • 组件可以使用vue选项(没有el)
    • 有自己的选项,如template(要求有一个根元素)
  • data(){return{数据a:值}}
  • 尽可能的使用第三方组件element-ui/mint/iview

3.全局组件:定义位置在newVue之前

  • 定义组件Vue.component()
  • 封装的具体内容(通过选项完成)

4.局部组件:通过选项component

  • 注册局部组件:{组件名:{选项}}
  • 设置选项{template或者data等}
  • 使用组件 <组件名></组件名>

5.组件嵌套

  • newVue所管理的视图相当于整个项目的根组件
  • 组件是父组件还是子组件与该组件在视图中使用的位置有关系,与该组件是全局还是局部组件没有关系

6.组件通信

  • 兄弟组件之间 组件a->组件b
  • 父子组件之间 父->子 子->父
  • 隔代租价之间 爷->父->子

7.组件和模块的区别

  • 模块:具有独立功能的js文件 比如math.js
  • 组件:封装的时html/css/js

八、组件的形式:

slot:插槽

简介通过插槽分发内容,将 <slot> 元素作为承载分发内容的出口。插槽内可以包含任何模板代码,包括 HTML,甚至是组件。

场景:和 HTML 元素一样,我们经常需要向一个组件传递内容。

基础案例:

//插入文本
<navigation-link url="/profile">
  Your Profile
</navigation-link>

//插入HTML
<navigation-link url="/profile">
  <!-- 添加一个 Font Awesome 图标 -->
  <span class="fa fa-user"></span>
  Your Profile
</navigation-link>

//插入组件
<navigation-link url="/profile">
  <!-- 添加一个图标的组件 -->
  <font-awesome-icon name="user"></font-awesome-icon>
  Your Profile
</navigation-link>


//navigation-link组件里面
<a v-bind:href="url" class="nav-link">
  <slot></slot>
</a>

解析:slot会被替换成Your Profile”。

注意事项:如果 <navigation-link>template没有包含一个 <slot> 元素,则该组件起始标签和结束标签之间的任何内容都会被抛弃。

1.编译作用域(了解)

场景:在插槽使用数据时。

注意事项:该插槽跟模板的其它地方一样可以访问相同的实例 property (也就是相同的“作用域”),而不能访问 <navigation-link> 的作用域。例如 url 是访问不到的:

案例代码:

<navigation-link url="/profile">
  Logged in as {{ user.name }}
</navigation-link>


<navigation-link url="/profile">
  Clicking here will send you to: {{ url }}
  <!--
  这里的 `url` 会是 undefined,因为其 (指该插槽的) 内容是
  _传递给_ <navigation-link> 的而不是
  在 <navigation-link> 组件*内部*定义的。
  -->
</navigation-link>

//父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。
2.后备内容:

作用:设置具体的后备 (也就是默认的) 内容是很有用的,它只会在没有提供内容的时候被渲染。

案例:

<button type="submit">
  <slot>Submit</slot>
</button>

//现在当我在一个父级组件中使用 <submit-button> 并且不提供任何插槽内容时:
<submit-button></submit-button>
    
//但是如果我们提供内容:
<submit-button>
  Save
</submit-button>
3.具名插槽:

场景:需要使用多个插槽的时候。

特别注意:v-slot 只能添加在 <template>

缩写:参数之前的所有内容 (v-slot:) 替换为字符 #。例如 v-slot:header 可以被重写为 #header

案例

<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

解析:一个不带 name<slot> 出口会带有隐含的名字“default”。

在向具名插槽提供内容的时候,我们可以在一个 <template> 元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称:

<template> 元素中的所有内容都将会被传入相应的插槽。任何没有被包裹在带有 v-slot<template> 中的内容都会被视为默认插槽的内容。

如果你希望更明确一些,仍然可以在一个 <template> 中包裹默认插槽的内容:

<base-layout>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>

  <template v-slot:default>
    <p>A paragraph for the main content.</p>
    <p>And another one.</p>
  </template>

  <template v-slot:footer>
    <p>Here's some contact info</p>
  </template>
</base-layout>
4.作用域插槽:

作用:在父容器内,在当前组件上使用当前组件(即子组件)内的数据(让插槽内容能够访问子组件中才有的数据)。

**解决方案:**为了让 user 在父级的插槽内容中可用,我们可以将 user 作为 <slot> 元素的一个 attribute 绑定上去:

<span>
  <slot v-bind:user="user">
    {{ user.lastName }}
  </slot>
</span>

//父容器内的组件
<current-user>
  <template v-slot:default="slotProps">
    {{ slotProps.user.firstName }}
  </template>
</current-user>

解析:绑定在 <slot> 元素上的 attribute 被称为插槽 prop。现在在父级作用域中,我们可以使用带值的 v-slot 来定义我们提供的插槽 prop 的名字。我们选择将包含所有插槽 prop 的对象命名为 slotProps,但你也可以使用任意你喜欢的名字。default为默认的插槽内容(数据)

出现多个插槽时:

<current-user>
  <template v-slot:default="slotProps">
    {{ slotProps.user.firstName }}
  </template>

  <template v-slot:other="otherSlotProps">
    ...
  </template>
</current-user>
5.解构插槽prop:

动态组件:

简介:多个组件通过同一个挂载点进行组件的切换,is的值是哪个组件的名称,那么页面就会显示哪个组件。

场景:需要根据数据,动态渲染的场景,组件类型不确定。

使用方式:使用 is attribute 来切换不同的组件.

案例:希望那些标签的组件实例能够被在它们第一次被创建的时候缓存下来,可以用一个 <keep-alive> 元素将其动态组件包裹起来

<!-- 失活的组件将会被缓存!-->
<keep-alive>
  <component v-bind:is="currentTabComponent"></component>
</keep-alive>

//currentTabComponent 组件名

异步组件:

简介:Vue 允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义。Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染。

场景:import函数,按需加载,异步加载大组件,vue常用性能优化方案之一。

 components: {
        FromDemo: () => import('./NextTick')
    }
//组件别名:FromDemo;引入的组件import('./NextTick')

九、组件间的数据传递:

解析:组件的关系 父子 爷孙 兄弟

1.父子组件间传递:

**解析:**父子关系,需要在父组件中引入子组件,此时组件间才算是父子关系。

使用的方式:props — this.$emit

//script
//导入子组件
import comChild from './comChild'

//注册子组件
components:{
    comChild
}

//templated
//使用已经注册的组件
<comChild />

父->子: 利用的是 v-bind 的动态数据绑定,以及props来接收数据。

步骤

1.向子组件传递数据:

​ 语法:

​ 解析:list为传递数据的 标识名,arr为传递的数据

2.在子组件中取出数据:

​ 语法:

// props:['list'] //第一种写法
    props:{
        list:{
            type:Array, //设置数据类型
            default(){
                return [] //给默认值
            }
        }
    }

​ 解析:props的用法与data中的数据一致。

子->父: 利用的是this的实例方法**$emit** 来发送数据,以及**v-on(@)**来监听事件的触发

步骤

1.向子组件中使用this.$emit方法,传递数据:

​ 语法:this.$emit(‘add’,this.num)

​ 解析:该方法一般放置在函数里面,该函数被触发时,即可向父级发送数据。add:数据的标识名,this.num:传递的数据

//template
<button @click="fan">发送数据</button>

//script
methods:{
     fan(){
        this.$emit('add',this.num)            
    }
}

2.父组件中取出数据:

​ 解析:使用v-on(@):来监听标识名,一旦被触发,则会执行add1函数,并传递一个实参。

​ 语法:

//template
<comChild @add="add1"/>

//script
add1(num){
    console.log(num)
    num = this.number++
    this.list.push({
        id:num,title:`标题${num}`
    })
}

2.中央事件总线:

解析:主要是用来处理非父子组件间的通信:爷孙组件、兄弟组件 (未解决)

**本质:**中央事件总线(通俗讲就是:eventBus事件车)的实质就是创建一个vue实例,通过一个空的vue实例作为桥梁实现vue组件间的通信。它是实现非父子组件通信的一种解决方案。

注意事项

//vue2.x中 引入vue并导出
import Vue from 'vue'
export default new Vue();

//vue3.x中 引入vue并导出
//Vue3项目注册全局组件时使用Vue时报错"export 'default' (imported as 'Vue') was not found in 'vue',
//原因:脚手架版本太高,需要卸载现在的脚手架版本,重新安装
npm uninstall -g @vue/cli
npm install -g @vue/cli@3.0.4

import Vue from 'vue'
export const eventBus = new Vue() //es6 新语法

步骤一:在main.js(或创建新的js文件)中创建Vue实例,作为桥梁实现vue组件的通信.

代码

import Vue from 'vue'

export default new Vue();//暴露一个实例

步骤二:使用$emit发送数据到其它组件,发送端需要设置在页面销毁前将 该通信进行销毁。

代码

//引入Vue实例,同时给一个别名
import eventBus from '../../event'

//触发事件的函数
messageSister(){
    eventBus.$emit('brotherSaid','妈妈说,该做作业了')
}

//销毁 $off
beforeDestroy(){
    eventBus.$off('brotherSaid','妈妈说,该做作业了')
}

步骤三:设置接收端 $on,兄弟组件触发了‘brotherSaid’事件,既可以响应接受到了数据。

代码

//组件生命周期created,此时可以接受到数据
created(){
    eventBus.$on('brotherSaid', (message) => {
        //注意先定义好接收数据:当前组件数据中 fromBrother:''
        console.log(message)
    })
}

解析:‘brotherSaid’:发送的一个共同的属性名,只有使用相同的属性名才能监听获取到数据

3.多层嵌套 数据从顶向下。

解析:该方法数据只能从顶层向下面的子代组件传输数据,不能向上传输,以此具有一定的局限性。使用的方法:provide()和inject

组件结构

//简写
<com1>
    <com2>
    	<com3></com3>
    </com2>
</com1>

//该代码显示com3是com1的孙辈,因此为嵌套关系

步骤一:在顶层(发送数据端)编辑好发送的数据内容,通过一个自定义的标识名

代码

provide(){
    return{
        elparrent:this
    }
}

//解析:provide使用的方法名;elparrent发送端的标识名,用于给接送端传递数据;this为发送的数据,是当前的vue实例,能够调用到所有的数据(函数、数据)

**步骤二:**在接受端接受数据,使用的是inject实例选项。

代码

inject:['elparrent']

//使用时
changeHander(){
    this.elparrent.changeFun()
}

//解析:inject实例选项,elparrent发送端的标识名,使用this来使用即可

4.父子组件间的传递- p a r e n t + parent+ parent+children[n],为直接取值方式

    3.1.父组件:console.log(this.$children[0].name); 使用 <this.$children[0].name>来进行访问,其中[0]为该组件中的第一个子组件,.name为子组件中的数据
    3.2.子组件:const {number} = this.$parent; 原理与取子组件的数据一致

5.孙辈之间的数据传递: (未解决)

    4.1.在 爷组件向父组件传递数据的方式 与 父子组件间数据传递一致 <onece :user="user"></onece>,爷向孙组件传递数据时,父组件起到了一种 数据中介的作用,所以,在父组件中,数据的传输为:<孙组件 v-bind='$attrs'>,孙组件使用数据可以为 {{$attrs.user}},
    <s特别注意:使用 $attrs 后不能使用 props 来继续接收该数值:user , 不然会被拦截>

十、spa-路由的应用

单页应用SPA

原理:前后端分离+前端路由,前端路由:根据不同的标识去渲染不同的组件。

好处

1.用户操作更方便 2.完全的前端组件化

缺点

1.首次加载大量资源 2.对搜索引擎SEO不友好 3.开发难度相对较高。

router功能作用:

  1. 实现单页面的切换

  2. 路由携带参数

  3. 路由的导航守卫

  4. 路由进行数据预载(进入组件前就请求获得数据)

路由:to属性

介绍:用于指定路由路径,以及传递参数

例子:Go to Foo

  • to值可以是固定的字符串
  • to值可以是data中的数据 :to=‘data中的数据’
  • to的值可以是{path:‘标识’} :to="{path:‘标识’}"
  • to的值可以是{name:‘路由配置的名字’} :to="{name:“路由器配置的名字”}"

路由模式

hash模式(默认) 例如:http://abc.com/#/user/10
h5 history模式  例如:http://abc.com/user/20 需要server端支持

注意:history有如下问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RfE3sttG-1619607904213)(img\1602245274479.png)]

路由的基本使用:

HTML
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>

<div id="app">
  <h1>Hello App!</h1>
  <p>
    <!-- 使用 router-link 组件来导航. -->
    <!-- 通过传入 `to` 属性指定链接. -->
    <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
    <router-link to="/foo">Go to Foo</router-link>
    <router-link to="/bar">Go to Bar</router-link>
  </p>
  <!-- 路由出口 -->
  <!-- 路由匹配到的组件将渲染在这里 -->
  <router-view></router-view>
</div>
JavaScript
// 0. 如果使用模块化机制编程,导入Vue和VueRouter,要调用 Vue.use(VueRouter)

<!---- 下面这部分的内容 一般生成一个独立的js文件
// 1. 定义 (路由) 组件。
// 可以从其他文件 import 进来 (常用)
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }

// 2. 定义路由
// 每个路由应该映射一个组件。 其中"component" 可以是
// 通过 Vue.extend() 创建的组件构造器,
// 或者,只是一个组件配置对象。
// 我们晚点再讨论嵌套路由。
const routes = [
  { path: '/foo', component: Foo },
  { path: '/bar', component: Bar }
]

// 3. 创建 router 实例,然后传 `routes` 配置
// 你还可以传别的配置参数, 不过先这么简单着吧。
const router = new VueRouter({
  routes // (缩写) 相当于 routes: routes
})
--------------------------->

// 4. 创建和挂载根实例。
// 记得要通过 router 配置参数注入路由,
// 从而让整个应用都有路由功能
const app = new Vue({
  router
}).$mount('#app')

// 现在,应用已经启动了!

动态路由匹配:

案例代码:

const User = {
  template: '<div>User</div>'
}

const router = new VueRouter({
  routes: [
    // 动态路径参数 以冒号开头
    { path: '/user/:id', component: User }
  ]
})

解析:一个“路径参数”使用冒号 : 标记。当匹配到一个路由时,参数值会被设置到 this.$route.params

路由对象属性:
属性名类型作用
$route.pathstring字符串,对应当前路由的路径,总是解析为绝对路径,如 "/foo/bar"
$route.paramsObject一个 key/value 对象,包含了动态片段和全匹配片段,如果没有路由参数,就是一个空对象。
$route.queryObject一个 key/value 对象,表示 URL 查询参数。例如,对于路径 /foo?user=1,则有 $route.query.user == 1,如果没有查询参数,则是个空对象。
$route.hashstring当前路由的 hash 值 (带 #) ,如果没有 hash 值,则为空字符串。
$route.fullPathstring完成解析后的 URL,包含查询参数和 hash 的完整路径。
$route.redirectedFrom如果存在重定向,即为重定向来源的路由的名字。(参阅重定向和别名)
$route.name当前路由的名称,如果有的话。(查看命名路由)

嵌套路由:

使用场景:相同路由匹配多个路由组件

案例代码

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

export default router = new Router({
  routes: [
    {
      path: '/user/:id',
      component: User,
      children: [
        {
          // 当 /user/:id/profile 匹配成功,
          // UserProfile 会被渲染在 User 的 <router-view> 中
          path: 'profile',
          component: UserProfile
        },
        {
          // 当 /user/:id/posts 匹配成功
          // UserPosts 会被渲染在 User 的 <router-view> 中
          path: 'posts',
          component: UserPosts
        }
      ]
    }
  ]
})

解析children 配置就是像 routes 配置一样的路由配置数组,所以呢,你可以嵌套多层路由。

编程式导航:

介绍:实现导航链接的方式:<router-link>,还可以借助 router 的实例方法。

声明式编程式
<router-link :to="...">$router.push(...)

push跳转会有历史记录,repalce没有历史记录,没有返回上一步。

声明式编程式
<router-link :to="...">$router.replace(...)

案例

this.$router.push('/demo')
this.$router.push({path:'/demo'})
this.$router.push({name:'demo'})

//放置在函数中

路由:重定向

介绍:强制修改url标识 重新发起请求,

例如:

path:’/’ 希望渲染首页 -> comA组件 ;

{patn:‘/’,redirect:{name/path:值}}

路由:传参

1.router-link

:to="{name:‘routerdemo2’,query:{id:‘1234’}}"
:to="{name:‘routerdemo1’,params:{name1:‘张三’}}"

注意:params传递参数不能刷新,参数在url上显示;query是可以的,参数在url上显示;使用path跳转不能使用params传参。

2.编程式导航:

案例

this.$router.push({
    path:'/demo2',
    query:{
           id:'6666',
           name:'张三'
         }
    })

路由守卫:

全局前置守卫

**场景:**检测用户登录状态 检测用户有没有账号

router.beforeEach((to,from,next) =>{

  // console.log(to) //当前路由对象

  // console.log(from)//上一个路由对象

  // console.log(next)//跳到下一个路由守卫

   next() //必须要有

})

十一、网络请求

​ 1.在Vue中发送网络请求
​ 1)接口服务器
​ 2)明确接口规则是什么
​ 3)postman->测试接口
​ 2.json-server(json服务器):把json文件转换为服务器接口
​ 1.npm i -g json-server(不行,添加环境变量,得下载nodejs)
​ 2.新建路径(自定义)已经db.json(文件中添加https://github.com/typicode/json-server网址所要求)
​ 3.在代码目录下新建了server文件夹->db.json
​ 4.以管理员身份下打开 powershell,运行json-server --watch db.json,不行则要蛇形策略更改
​ 5.端口号冲突:json-server --watch --port 3001 db.json
​ 3.RESTFulJ接口规则
​ 1.json-server工具应用了RESTFul接口规则
​ 2.特点:只需要关心请求方式是什么,而不需要关注标识url
​ 3.post增加 delete删除/1 put修改/1 get查询/1 模糊搜索?name_like=关键字
​ 4.axios介绍
​ axios不是vue插件 可以在客户端和服务端使用 不支持jsonp
​ 5.jsonp:跨域 原型
​ 8种解决方案:1.jsonp -> script src="" -> callback()
​ 1.使用前提:接口要支持jsonp
​ 2.get
​ 2.服务端处理 3.iframe src=“xxx.html”+location.hash
​ 4.设置代理 转发 5.iframe+window.name 6.
​ 6.异步操作
​ 要在异步操作的外部获取到异步操作的结果->异步编程->callback->修改axios中的.then()方法的源码(不合理)
​ 异步操作场景:1.ajax 2.定时器 3.点击事件 4.数据库操作
​ 特点:代码不等待 后续代码会继续执行

十二、组件生命周期方法

创建期间的生命周期

1、beforeCreate

调用时间:Vue实例刚刚被创建好,同时事件和生命周期方法初始化完毕后,开始调用。
特点:这时data和methods属性还没初始化完毕

2、created

调用时间:data和methods属性刚初始化完毕。
特点:最早可以访问数据(data)和方法(methos)的生命周期。

3、beforeMunt

调用时间:虚拟DOM已经创建完毕,但还没渲染、挂载到页面。

4、mounted

调用时间:此时vue已经完成了模板的渲染。
特点:可以拿到页面上的数据。

运行期间的生命周期方法

1、beforeUpdate

调用时间:当数据发生变化时
特点:只有保存的数据改变的时候,才会被调用,此时页面还没更新

2、updated

调用时间:实例数据更新到页面,并完成的时候
特点:数据和页面都同步更新,保持一致

3、activated

调用时间:keep-alive组件激活时调用。类似v-show.该钩子在服务器端渲染期间不被调用

销毁期间的生命周期方法

1、beforeDestroy

调用时间:当前组件将要销毁
特点:用于销毁一些需要一致循环的函数,或需要获取该组件中不存在元素的函数判断,例如定时器等;最后能够访问组件数据和方法的函数。

2、destroyed

调用时间:当前组件已经被销毁了
特点:不要在这个生命周期中操作组件和数据

单组件声明周期图

挂载: beforeCreate => created => beforeMount => mounted
更新: beforeUpdate => updated
销毁: beforeDestroy => destroyed

十三、vuex状态管理:

介绍

  • Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。

  • 它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

  • Vuex 也集成到 Vue 的官方调试工具 devtools extension (opens new window),提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能

  • Vuex有五个核心概念,state, getters, mutations, actions, modules。

  • 状态管理: 简单理解就是统一管理和维护各个vue组件的可变化状态(你能够理解成vue组件里的某些data)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AMddDNuE-1619607904217)(img\1602244775741.png)]

store仓库:

介绍:每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。Vuex 和单纯的全局对象有以下两点不同:

  1. Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。

  2. 你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用.

基本使用:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count: 0
  },
  getters:{
        getCount(state){
            return state.mycount
        }
    },
  mutations: {
    increment (state) {
      state.count++
    }
  }
})

核心概念:

1.state 单一状态树:

介绍:state为一个对象,包含了全部的应用层级状态,作为一个“唯一数据源 (SSOT (opens new window))”而存在。这也意味着,每个应用将仅仅包含一个 store 实例。单一状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照。

案例取值:

//方式一:
//直接取值,相当于data
this.$store.state.属性名
//取模块comm中的数据
this.$store.state.comm.属性名

//方式二:
this.$store.state['属性名']

//方式三:
//在computed中先做处理,在取值
import {mapState} from 'vuex'

computed:{
    ...mapState(['mycount'])
}

<p>mycount:{{mycount}}</p>
2.getter 缓存数据:

介绍:在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

案例取值:

//方式一:
//直接取值,相当于data
this.$store.getters.属性名

//方式二:
this.$store.getters['属性名']
//取模块comm中getter中的数据,分模块时必须使用
this.$store.getters['comm/getList']

//方式三:
//在computed中先做处理,在取值
import {mapGetters} from 'vuex'

computed:{
    ...mapGetters(['getCount'])
    
    //取模块comm中getter中的数据
    ...mapGetters('comm',['getList'])
}

<p>getCount:{{getCount}}</p>
3.mutations 状态改变:

介绍:更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。mutation必须是同步函数。

Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数

案例取值:

//方式一:
//触发一个类型为 increment 的 mutation 时,使用commit
this.$store.commit('事件名',参数)
//取模块comm中mutations 中的数据
this.$store.commit('comm/increment',10)

//方式二:
//在computed中先做处理,在取值
import {mapGetters} from 'vuex'

computed:{
    ...mutations(['事件名'])
}

<button @click="事件名">添加</button> 
Mutation 需遵守 Vue 的响应规则

既然 Vuex 的 store 中的状态是响应式的,那么当我们变更状态时,监视状态的 Vue 组件也会自动更新。这也意味着 Vuex 中的 mutation 也需要与使用 Vue 一样遵守一些注意事项:

  1. 最好提前在你的 store 中初始化好所有所需属性。
  2. 当需要在对象上添加新属性时,你应该
4.action 异步操作:

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。

案例代码:

//在methods调用
//Action 通过 store.dispatch 方法触发:
decrement(){
    this.$store.dispatch('research',2)
    //取模块comm中action中的数据
    this.$store.dispatch('comm/recrement',2)
}

//在vuex中声明
mutations:{
    research(state,num){
        state.mycount -= num
    }
},
actions:{
    research({commit},num){
        return commit('research',num)
    }
}
解析:commit来调用
5.module 模块:

解决的问题:由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。

Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:

案例

const moduleA = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
模块化使用:
//comm.js
const actions ……(下面)

export default {
    state,
    getters,
    mutations,
    actions,
    namespaced:true //模块化
}
//可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。

//全局性的vuex
import comm from './modules/comm'
export default new Vuex.Store({
    modules:{
        comm    //进行导入
    },
    ……

十四、vue的核心功能:

介绍:vue.js中有两个核心功能:响应式数据绑定,组件系统。主流的mvc框架都实现了单向数据绑定,而双向绑定无非是在单向绑定基础上给可输入元素添加了change事件,从而动态地修改model和view。

1. MVC,MVP,MVVM

1.1 MVC

MVC模式将软件分为下面三个部分

1.视图(View):用户界面
2.控制器(Controller):业务逻辑
3.模型(Model):数据保存

MVC各个部分之间通信的方式如下:

1.视图传送指令到控制器
2.控制器完成业务逻辑后要求模型改变状态
3.模型将新的数据发送到视图,用户得到反馈

示意图如下:

img

以上所有通信都是单向的。接受用户指令的时候,MVC有两种方式,一种是通过视图接受指令,然后传递给控制器。另一种是用户直接给控制器发送指令。

实际使用中可能更加灵活,下面是以Backbone.js为例说明。

1.用户可以向视图(View)发送指令(DOM事件),再由View直接要求Model改变状态。
2.用户也可以向Controller发送指令(改变URL触发hashChange事件),再由Controller发送给View。
3.Controller很薄只起到路由作用而View非常厚业务逻辑都放在View。所以Backbone索性取消了Controller,只保留了Router(路由器)

MVC模式体现了“关注点分离”这一设计原则,将一个人机交互应用涉及到的功能分为三部分,Model对应应用状态和业务功能的封装,可以将它理解为同时包含数据和行为的领域模型,Model接受Controller的请求并完成相应的业务处理,在应用状态改变的时候可以向View发出通知。View实现可视化界面的呈现和用户的交互操作,VIew层可以直接调用Model查询状态,Model也可以在自己状态发生变化的时候主动通知VIew。Controller是Model和View之间的连接器,用于控制应用程序的流程。View捕获用户交互操作后直接发送给Controller,完成相应的UI逻辑,如果涉及业务功能调用Controller会调用Model,修改Model状态。Controller也可以主动控制原View或者创建新的View对用户交互予以响应。

1.2 MVP

MVP模式将Controller改名为Presenter,同时改变了通信方向,如下图:

img

1.各部分之间的通信都是双向的。
2.视图(View)和模型(Model)不发生联系,都是通过表现Presenter)传递
3.View非常薄,不部署任何业务逻辑,称为被动视图(Passive View),即没有任何主动性,而Presenter非常厚,所有逻辑都这里

MVP适用于事件驱动的应用架构中,如asp.net web form,windows forms应用。

1.3 MVVM

MVVM模式将Presenter层替换为ViewModel,其他与MVP模式基本一致,示意图如下:

img

它和MVP的区别是,采用双向绑定视图层(View)的变动,自动反映在ViewModel,反之亦然。Angular和Vue,React采用这种方式。

MVVM的提出源于WPF,主要是用于分离应用界面层和业务逻辑层,WPF,Siverlight都基于数据驱动开发。

MVVM模式中,一个ViewModel和一个View匹配,完全和View绑定,所有View中的修改变化,都会更新到ViewModel中,同时VewModel的任何变化都会同步到View上显示。之所以自动同步是ViewModel中的属性都实现了observable这样的接口,也就是说当使用属性的set方法,会同时触发属性修改的事件,使绑定的UI自动刷新。

响应式数据绑定:

组件系统:

十五、项目总结:

1.关于登录页面的验证:

**

1.1 MVC

MVC模式将软件分为下面三个部分

1.视图(View):用户界面
2.控制器(Controller):业务逻辑
3.模型(Model):数据保存

MVC各个部分之间通信的方式如下:

1.视图传送指令到控制器
2.控制器完成业务逻辑后要求模型改变状态
3.模型将新的数据发送到视图,用户得到反馈

示意图如下:

[外链图片转存中…(img-64IyTq7b-1619607904219)]

以上所有通信都是单向的。接受用户指令的时候,MVC有两种方式,一种是通过视图接受指令,然后传递给控制器。另一种是用户直接给控制器发送指令。

实际使用中可能更加灵活,下面是以Backbone.js为例说明。

1.用户可以向视图(View)发送指令(DOM事件),再由View直接要求Model改变状态。
2.用户也可以向Controller发送指令(改变URL触发hashChange事件),再由Controller发送给View。
3.Controller很薄只起到路由作用而View非常厚业务逻辑都放在View。所以Backbone索性取消了Controller,只保留了Router(路由器)

MVC模式体现了“关注点分离”这一设计原则,将一个人机交互应用涉及到的功能分为三部分,Model对应应用状态和业务功能的封装,可以将它理解为同时包含数据和行为的领域模型,Model接受Controller的请求并完成相应的业务处理,在应用状态改变的时候可以向View发出通知。View实现可视化界面的呈现和用户的交互操作,VIew层可以直接调用Model查询状态,Model也可以在自己状态发生变化的时候主动通知VIew。Controller是Model和View之间的连接器,用于控制应用程序的流程。View捕获用户交互操作后直接发送给Controller,完成相应的UI逻辑,如果涉及业务功能调用Controller会调用Model,修改Model状态。Controller也可以主动控制原View或者创建新的View对用户交互予以响应。

1.2 MVP

MVP模式将Controller改名为Presenter,同时改变了通信方向,如下图:

[外链图片转存中…(img-B1xfXufM-1619607904221)]

1.各部分之间的通信都是双向的。
2.视图(View)和模型(Model)不发生联系,都是通过表现Presenter)传递
3.View非常薄,不部署任何业务逻辑,称为被动视图(Passive View),即没有任何主动性,而Presenter非常厚,所有逻辑都这里

MVP适用于事件驱动的应用架构中,如asp.net web form,windows forms应用。

1.3 MVVM

MVVM模式将Presenter层替换为ViewModel,其他与MVP模式基本一致,示意图如下:

[外链图片转存中…(img-vGVko23f-1619607904222)]

它和MVP的区别是,采用双向绑定视图层(View)的变动,自动反映在ViewModel,反之亦然。Angular和Vue,React采用这种方式。

MVVM的提出源于WPF,主要是用于分离应用界面层和业务逻辑层,WPF,Siverlight都基于数据驱动开发。

MVVM模式中,一个ViewModel和一个View匹配,完全和View绑定,所有View中的修改变化,都会更新到ViewModel中,同时VewModel的任何变化都会同步到View上显示。之所以自动同步是ViewModel中的属性都实现了observable这样的接口,也就是说当使用属性的set方法,会同时触发属性修改的事件,使绑定的UI自动刷新。

响应式数据绑定:

组件系统:

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值