vue笔记

模块

用来封装可以重复使用的js代码块

模块的分类:

es模块化

comment 模块化

项目启动方式修改

进入项目的package.json中修改 scripts项即可

优雅降级 渐进增强

淘宝镜像

npm的服务器在国外 我们国内连接可能会很慢

淘宝在这个时候他有一个服务器在国内 这个服务器会每隔10分钟自动从npm的服务器上拉取最新的所有内容

我们可以直接访淘宝在国内的这个服务器 这样一来下载的速度就会很快

使用:

打开cmd npm install -g cnpm
–registry=https://registry.npm.taobao.org

数组解构

let demo=[1,2,3,4]

let [a,b,c,d]=demo

let arr=[1,[2,3,[4,[5,[6,],7]]],8,[9]] 使用解构把这些数据分别赋值给a-i 这9个变量怎么办?

let [a,[b,c,[d,[e,[f,],g]]],h,[i]] =arr

html5新增特性 本地存储

可以在本地浏览器中存储5mb的数据

分类:

1.locationStorage:永久存储 浏览器关闭不丢失 存储得数据只要是一个项目的内容都可以用

2.sessionStoreage:临时存储(会话存储)浏览器关闭数据丢失 存储的数据谁存的只能谁用

方法:

取数据使用getItem

存数据使用setitem

项目原型设计

墨刀 墨客 。。。。n个

vue笔记

基本概念

Vue.js是目前最流行的前端MVVM框架

是一套构建用户界面的渐进式自底向上增量开发MVVM框架

渐进式:可以在原有大系统的上面,把一两个组件改用vue实现,也可以整个用vue全家桶开发不会做职责之外的事

自底向上增量开发:先写一个基础的页面,把基础的东西写好,再逐一去添加功能和效果,由简单到繁琐的这么一个过程。

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

目的

Vue.js的产生核心是为了解决如下三个问题
1.解决数据绑定问题。
2.Vue.js主要的目的是为了开发大型单页面应用。
3.支持组件化,也就是可以把页面封装成为若干个组件,把组件进行拼装,这样是让页面的复用性达到最高。

MVVM

M: model 模型等同于数据 m层的作用就是用来管理数据

V: view 视图层 就等同于用户可以看见的内容区域

VM:viewModel 视图模型层 相当于 用户看见的视图层与模型层之间的数据通信桥梁

Helloword

1.下包vue 所有的依赖全部要交由npm管理

(1)npm init -y

{2) npm install --save vue

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>Documenttitle>
    
    <script src="node_modules/vue/dist/vue.js">script>
head>
<body>
    


    
    <div id="demodiv">
        <h1>{{num}}h1>
        <h1>{{text}}h1>
        <h1>{{arr[2]}}h1>
    div>

    <script>
        // 3.新建vm层  视图模型层 他就是vue实例
        new Vue({
            el:"#demodiv",//关联视图层
            data:{ //m层  模型层
                text:"我是一个字符串",
                num:18,
                bool:true,
                arr:[1111,2222,3333,4444],
                obj:{
                    name:"xixi",
                    age:18
                }
            }
        })

    script>

body>
html>

Vue声明式渲染

命令式渲染 : 命令我们的程序去做什么,程序就会跟着你的命令去一步一步执行
声明式渲染 : 我们只需要告诉程序我们想要什么效果,其他的交给程序来做。

数据驱动

通过控制数据的变化来显示vue的数据驱动是视图的内容随着数据的改变而改变

{{}}---- 模板语法

{{}}中方的是表达式

什么是表达式?

通过计算可以返回结果的内容

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>Documenttitle>
    <script src="node_modules/vue/dist/vue.js">script>
head>
<body>
    <div id="dmeodiv">
        <h1>{{}}中方的都是表达式h1>
        <h1>{{text}}h1>
        <h1>{{text.toUpperCase()}}h1>

        <h1>{{bool}}h1>
        <h1>{{bool?'你好':"你坏"}}h1>
    div>
    <script>
        new Vue({
            el:"#dmeodiv",
            data:{
                text:"abcdefg",
                bool:false
            }
        })

    script>
body>
html>

注意

避免在双括号中使用复杂表达式

常见问题

如何区分插值中的内容是表达式还是普通文本?
Vue.js 会通过是否带引号区分两者

指令

与本节课无关

什么是HTML标签的属性?

就是用来扩展html标签的功能

属性的语法?

写在html的开标签中 并且属性=“属性值” 多个属性用空格隔开

指令的基本概念

就是在vue中使用v-开头的htmnl特殊属性 作用就是扩展html的功能

指令的语法?

写在html的开标签中 并且v-指令=“指令值” 多个指令用空格隔开

v-model

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>Documenttitle>
    <script src="node_modules/vue/dist/vue.js">script>
head>
<body>
    <div id="dmeodiv">
        <h1>v-mode主要是用于表单上数据的双向绑定h1>
        <h1>
            v-model可以完成双向绑定
            模型和视图
            模型变了---》视图就会自动发生改变
            视图变了---》模型也会自动改变
        h1>

        <input type="text" v-model="text"/>
        <h1>{{text}}h1>
    div>
    <script>
        new Vue({
            el:"#dmeodiv",
            data:{
               text:"你好么么哒"
            }
        })

    script>
body>
html>

双向绑定的原理

数据劫持:当我们访问或设置对象的属性的时候,都会触发**Object.defineProperty()**函数来拦截(劫持),然后在 返回(get)或设置(set)对象的属性的值。并且当数据发生改变的时候做出反应。

发布者-订阅者模式:其定义对象间一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。

v-show

  • 作用:控制切换一个元素的显示和隐藏;

  • v-show=表达式

  • 根据表达式的真假,确定是否显示当前元素;

  • true表示显示该元素;false表示隐藏;

  • 元素一直存在只是被动态设置了display:none;

v-on

  • 作用:为 HTML 元素绑定事件监听
  • 语法:v-on:事件名称=“函数名称()”——v-on:click=“fun()”
  • 简写:@事件名称=“函数名称()”——@click=“funb()”
  • 函数fun()写在methods中;

v-for

  • 遍历data中的数据,并再页面中进行数据展示;
  • v-for="(item,index) in arr";

v-bind

  • 绑定HTML元素的属性;
  • v-bind:属性名=“表达式”;
  • 简写::属性名=“表达式”;
<a v-bind:href="aherf">{{atext}}</a>
<a :href="aherf">{{atext}}</a>

v-if

  • 作用:判断你是否加载固定的内容;

  • v-if=表达式;

    • true——表示加载该元素;
    • false——表示不加载该元素;

v-else

  • 作用:必须配合v-if使用;当v-if条件不成立的时候执行;
  • v-if 和 v-else——中间不能有多余的内容;

v-else-if

  • 作用:当只有一项成立的时候执行;

v-text

  • 作用:操作网页元素的纯文本内容;{{}}是他的另外一种写法;

  • v-text:指令;{{}}——模板插值;

  • 区别:渲染数据比较多的时候,可能会把{{}}显示出来,俗称屏幕闪动;{{text}

  • 屏幕闪动:

    • 解决:

      • ①使用v-text渲染数据;

      • ②使用{{}}语法渲染数据,但是同时使用v-cloak指令,

        • 位置:在el挂载的标签上添加;
        • 还需要设置CSS样式:
1.位置
<div id="demodiv" v-cloak>
</div> 
2.CSS 
[v-cloak]{
	display:none; 
} 

v-html

为了输出真正的HTML

{{}}只会输出纯文本

v-once

数据发送改变的时候,插值出内容不会更新

watch监听

watch:监听data里面的数据,如果data数据改变,watch就会触发;

计算属性——语法:

  • 计算属性:是一个带有计算功能的vue的实例的属性; 可以计算data模型中的数据; 当一条data数据在不同的位置想要展现不同的形态的时候;
  • 当这个属性(data中的数据text)发生改变,计算属性也会随之变化;
computed:{
    需要返回的数据:function(){
        return  处理操作
    }
}

计算属性和方法的区别

区别
方法 只要调用就会执行,浪费性能
计算属性 有缓存;使用计算属性的时候会执行一次,只要数据没有改变,多次调用的时候就会从缓存中读取;所依赖的值发生改变才触发调用函数;
watch 初始化的时候不会运行,只有数据被改变之后才会运行;监听的值发送该斌就会调用这个函数;

事件对象

  1. 按键修饰符.up、.down、.enter、.space、.ctrl——语法:@click.修饰符=‘fn()’

  2. 事件修饰符:

  • prevent:阻止事件的默认行为(submit提交表单)
  • stop:阻止事件冒泡
  • capture:与事件冒泡的方向相反
  • self:只会触发自己范围内的事件,不包含子元素
  • once:只会触发一次

过滤器

  1. 概念:在不改变原始数据的情况下,格式化展示数据;

2.0中已经废弃了内置过滤器,

  1. 自定义过滤器
  • 全局过滤器:在所有的vue实例中都可以使用; 位置:创建实例之前
  • 过滤器的使用:{{数据|过滤器的名字}}
Vue.filter("过滤器的名字",(要过滤的数据)=>{
        return 你的逻辑
})
//  全局过滤器
Vue.filter("filt", (val) => {
    return "¥" + val
})

局部过滤器:只在当前的vue实例区域中可以使用;
位置;写在当前vue的el data 的同级位置;

filters:{
    过滤器的名字(要过滤的数据){
        return 你的逻辑
    }
}

实例的生命周期

  1. 生命周期:实例在创建到销毁的全过程。

  2. 生命周期钩子:在生命周期中被自动调用的函数。

    • 作用:提供执行自定义逻辑的机会。
    • 书写位置:在data与methods同级位置书写。
  3. 钩子函数

页面已进入就触发beforeCreated、created、beforeMount、mounted;

  • beforeCreate:创建实例。
  • created:创建完成。此时视图中 的HTML还没有渲染出来,不能操作dom。
  • beforeMount:模板渲染。
  • mounted:渲染完毕。此时可以操作dom。(此阶段可以发送请求)
  • beforeUpdate:开始更新。
  • updated:更新完成。
  • beforeDestroy:开始销毁。
  • destroy:销毁完成。

vue-cli

脚手架创建

下载4.0
vue-cli@4————开发环境
在cmd中
(1)全局安装脚手架:cnpm install -g @vue/cli——(只需要执行一次)
(2)查看版本:vue --version
(3)cd 到你要创建的项目文件夹下(/在vscode集成终端打开)
(4)vue create 你的项目名(不要有大写)
————(选择第三个features之后,一路回车)
(5)下载好后,cd到项目名
(6)npm run serve ——启动项目

单文件组件

就是以.vue结尾的文件;
template是写html的;script是写js的;style是写样式的;
删除默认项目

组件——用来封装可以重复使用的内容;本质:自定义标签;

怎么写?——组件写在componts下,以.vue结尾;
怎么使用?——1.引用;2.调用;3.使用;
1.引用——import 起名字(Com) from 你引用文件的地址(components/com.vue);
2.调用——components:{引用组件的名字(Com),Com1,Com2,…}
3.使用——或者

坑1——template中如果有多行标签,必须有父节点包裹
坑2——想在组件中使用data模型数据怎么办???
只有data有变化:写成函数

export default{
    components:{
        引用组件的名字(Com),
        Com1,...
    },
    data(){
        return{
            变量名:变量值,
            text:"文本"}
    }
}

vue 组件中的 data 为什么必须是函数

在说之前我先讲讲深拷贝和浅拷贝

在 javascript 里面简单数据类型的拷贝一般使用浅拷贝,复杂类型一般使用深拷贝,请看例子

var a = 0;
var b = a;
b = 1
console.log('a···' + a,'b···' + b) //a···0 b···1

可以看到我把 a 赋值给了 b ,修改了 b 的值后 a 的值没有变

var a = {
    name: '张三',
    age: '18'
};
var b = a;
b.name = '李四';
console.log(a.name) //李四

而在对象中我把 a 赋值给了 b ,修改了 b 的name 值后 a 的 name 值也变了

为什么基本数据类型的值没变,引用数据类型的值变了:

  • 基本数据类型是放在栈里面的,它是按值访问,在栈内存中发生复制行为时系统会为新的变量提供新值,所以两个变量互不影响
  • 引用数据类型是放在堆内存中的,它是按引用访问的,在栈内存中有一个地址是指向堆内存中的引用数据类型的,所以我们拷贝引用数据类型其实就是拷贝了栈内存中的地址,因为地址一样,他们都是指向同一个引用数据类型,所以两个变量会相互影响,这时就必须使用深拷贝了

如果能理解深浅拷贝就可以理解 data 为什么要用函数了???

在创建或注册模板的时候传入一个 data 属性作为用来绑定的数据。但是在组件中,data必须是一个函数,因为每一个 vue 组件都是一个 vue 实例,通过 new Vue() 实例化,引用同一个对象,如果 data 直接是一个对象的话,那么一旦修改其中一个组件的数据,其他组件相同数据就会被改变,而 data 是函数的话,每个 vue 组件的 data 都因为函数有了自己的作用域,互不干扰。

父子组件

组件与组件之间调用之后呈现的嵌套关系

父子组件的作用域

子组件和父组件是一个完整的独立的个体 组件与组件之间数据不能直接互通

扩展小知识

  1. 引用组件/路径时:@代表的就是src文件夹

  2. 全局样式**需要写在app.vue中(不加scoped)

  3. v-for key的使用

  • 为遍历数组或元素中的唯一标识,增加或删减元素时,通过这个唯一标识key判断是否是之前的元素,vue会直接对已有的标签进行复用,不会整个的将所有的标签全部重新删除和创建,只会重新渲染数据,然后再创建新的元素直到数据渲染完为止

组件传值----正向传值

  1. 正向传值:父组件把数据给子组件

  2. props:在子组件创建用来接受父组件传递的数据

props语法: 写在需要接受父组件数据的子组件中 与data methods等属性同级
props的本质是标签的属性

props:[接受的变量1,接受的变量2]

基本使用

子组件

<template>
  <div>
      <!-- 使用 -->
      homezi--{{title}}---{{num}}--{{sex}}
  </div>
</template>

<script>
export default {
    // 子组件设置好了接受
    props:["title","num",'sex']
}
</script>

<style>

</style>

父组件

<template>
  <div>
      home
      <!-- 在子组件被调用的地方 进行传递 -->
      <Homezi title="我是title" num="我是num" sex="我是sex"/>
  </div>
</template>

<script>
import Homezi from "./homezi.vue"
export default {
    components:{
        Homezi
    }
}
</script>

<style>

</style>

props 验证

在传统传值上 父组件给子组件任何数据类型都可以 没有任何约束 可能在今后展示上就会出现一些不可预知的错误

所以为了稳妥起见 我们在接收父组件数据的时候 给父组件传递过来的数据可以添加一个校验
验证传递过来的数据类型是否是我们想要的----props验证

props验证仅仅只会在控制台抛出一个警告 不会对我们显示造成影响 他就是给我们开发者一个提示

所以在上线的时候需要把props验证删除掉 vue的.min包 是不带props验证功能的

组件传值----逆向传值

子组件 把数据传递给父组件 默认情况下 逆向传值是不被允许的
如果硬要使用逆向传值 必须要有事件触发才可以

流程:

  1. 事件调用一个函数

  2. 抛出一个自定事件 $emit() 就是自定义事件 $emit(“自定义事件的名字随便起”,“参数”

<template>
  <div>
      子组件
      <!-- 1.事件触发函数 -->
      <button @click="fun()">点我逆向传值</button>
  </div>
</template>

<script>
export default {
    data(){
        return {
            zitext:"我是子组件的变量"
        }
    },
    methods:{
        fun(){
            // 2.抛出自定义事件
            this.$emit("xiaoming",this.zitext)
        }
    }
}
</script>

<style>

</style>
  1. 接收自定义事件 在子组件被调用的时候
<template>
  <div>
      父组件
<!-- 接收自定义事件  在子组件被调用的时候   
 <子组件调用的时候 v-on:子组件抛出的事件=“父组件的函数不加()不加()因为加了就默认值执行了”/> -->
      <Ez @xiaoming="emitfun"/>
  </div>
</template>

<script>
import Ez from "./emitzi.vue"
export default {
    components:{
        Ez
    },
    methods:{
        // 形参====子组件传递的数据
        emitfun(val){
            console.log(val)
        }
    }
}
</script>

<style>

</style>

slot----槽口/插槽

思考:组件的本质是自定义标签 标签有双标签和单标签 单标签是没有显示内容只有动作的标签 双标签则不然他是可以在开关标签中放置显示内容的
组件的调用可以是<组件名/> 也可以是 <组件名>
如果向组件中默认插入内容 h1是不会显示的

<template>
  <div>
      slot父
      <Slotzi>
          <h1>你好么么哒</h1>
      </Slotzi>
  </div>
</template>

我就是想让h1显示怎么办?

在这个时候就需要用slot组件来进行设置 slot是什么?slot就是组件中的一个开口 有了这个开口就可以接收外部插入的标签

在需要插入内容的组件中放置slot组件

<template>
  <div>
      slotzi
      <!-- 设置开口 -->
      <slot></slot>
  </div>
</template>

slot与props使用场景

  • 组件的数量相同内容不同的时候使用props
  • 组件的数量不同内容也不同的时候使用slot

具名slot

带有名字的slot/槽口

使用:

在定义slot的时候 使用name属性起个名字

在调用的时候使用slot属性插入对应内容

路由

之前我们学到的所有页面在vue的项目中只能显示一个 如何让vue显示多个页面 在这个时候我们就要使用路由技术

传统的页面跳转

  1. 使用标签的方式—》声明式 使用a标签 超连接标签

  2. 使用js的方式-------》编程式

  3. window.location.href=“xxxx地址” 修改当前url为你设置的参数

  4. window.history.replace() 替换当前的浏览器地址

  5. go()

什么是路由?

路由:所有的路径都经由这个模块进行重新分配(改变URL,在不重新请求页面的情况下,更新页面视图。)

根据url的不同来渲染不同的组件页面 完成 SPA(单页面应用) 的开发

创建路由

小概念:

  • 页面组件 :就是项目中的一个个页面整体 写在views文件夹下

  • 组件: 就是页面中一个个的ui部件 写在components文件夹下

1.vue-cli的方式:

只需要在创建的时候选择 Router这一项 即可
在路由配置文件中配置路由规则

 {
    path: '/',//路径  和url上面的路径进行匹配
    name: 'Home', //命名空间  给这个规则起个名字
    component: Home //调用的组件页面
  },

2.手工添加的方式(很重要 步骤要记住)

  1. 下载vue-router库 : npm install --save vue

  2. 新建路由页面组件

  3. 配置路由规则

//别忘了引用
const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  }
]
  1. 创建路由实例 并且把路由规则注入到路由实例中

  2. 把路由实例注入到vue实例中

  3. 设置路由出口

路由的导航

通过点击导航可以进行页面的跳转

1.声明式:(a标签)router-link to=“路径”;//写在展示的页面

 <router-link to="/home">home</router-link>
 <router-link to="/phone">phone</router-link>

如何知道当前是哪个页面??

  • 会自动在当前页面加一个router-link-active的类名;
    (方便设置样式)

2.编程式:

this.$router.push("/路径")this.$router.replace() 替换

this.$router.go()  正数前进   负数回退

404页面

给用户一个错误的提示页面,用通配符*, 但是要放在路由规则的最下面,因为路由规则的优先级是谁先定义谁的优先级高
但是有了404页面之后首次进入会先进入到404
因为:默认的路径式/,
但是刚进去的时候没有/,所以匹配不到任何路径,就会进入404页面

        // 404页面
        {
            path: '*',
            name: 'No404',
            component: No404
        }

重定向

重新定位方向

{

​	path:"/",

​	redirect("/去哪里")

}

多级路由

路由与路由之间有嵌套 通常多级路由是指 2级及以上的路由统称为多级路由

创建二级路由:

1.创建二级路由页面组件 views

2.配置二级路由的路由规则

​ (1)你要确定是那个一级路由的子路由 就在这个一路由的规则中进行创建

​ (2)创建children 并且进行引用

​ (3-1)路径中不加/

{
    path: '/user',
    name: 'User',
    component: User,
    // 二级路由
    children:[
      // 配置二级路由的规则(同一级路由)
      {
        // path不加/path不加/path不加/path不加/path不加/
        // path不加/path不加/path不加/path不加/path不加/
        // path不加/path不加/path不加/path不加/path不加/
        // path不加/path不加/path不加/path不加/path不加/
        path: 'era',
        name: 'Era',
        component: Era
      },
      {
        path: 'erc',
        name: 'Erc',
        component: Erc
      },
      {
        path: 'erd',
        name: 'Erd',
        component: Erd
      },
    ]

(3-2)path路径加/

 children:[
      // 配置二级路由的规则(同一级路由)
      {
        // path加/path加/path加/path加/
        // path加/path加/path加/path加/
        // path加/path加/path加/path加/
        // path加/path加/path加/path加/
        path: '/era',
        name: 'Era',
        component: Era
      },
      {
        path: '/erc',
        name: 'Erc',
        component: Erc
      },
      {
        path: '/erd',
        name: 'Erd',
        component: Erd
      },
    ]

(4) 设置二级路由的路由出口(1极路由在创建的时候vue脚手架会默认给我们添加 但是二级路由必须手工添加 二级路由的路由出口必须添加在它的一级路由之上)

(5)设置路由导航

​(5-1)(路径不加/,那么它的路径是/一级/二级)

 <router-link to="/wode/er1">我的er1</router-link>
      <router-link to="/wode/er2">我的er2</router-link>
      <router-link to="/wode/er3">我的er3</router-link>

(5-2) (路径加/,那么它的路径是/二级)

   <!-- 设置导航:路径加/,那么它的路径是/二级 -->
      <router-link to="/er1">我的er1</router-link>
      <router-link to="/er2">我的er2</router-link>
      <router-link to="/er3">我的er3</router-link>

路由模式

hash模式url里面永远带着#号,我们在开发当中默认使用这个模式。

history模式没有#号,是个正常的url适合推广宣传。(上了服务器之后会出现 做刷新操作,会出现404错误 让你们的服务器开发的那个人给你设置一下服务器上的重定向即可)

动态路由匹配/路由传参

把一个路由页面的数据传递到另外一个路由页面(有一个新闻列表页 点击其中的新闻标题 跳转到对应的新闻详情中)

params

实现:

(1)在路由规则中进行配置

	/:xxx自己定义参数
{
    path: '/all/:xiaoming',//路由传参的接收参数配置
    name: 'All',
    component: All
  },

(2)传递参数

​ (2-1)声明式

 <!-- 发送数据 -->
      <!-- 声明式方式1 了解 -->
      <router-link to="/all/我是传递给详情页得参数">点我用声明式方式1把数据给详情页</router-link>
      <!-- 声明式方式2 掌握 -->
      <!-- <router-link :to="{name:'你要跳转那个路径的名字',params:{你传递的key(要和路由配置一样):传递的值}}">点我用声明式方式2把数据给详情页</router-link> -->
      <router-link :to="{name:'All',params:{xiaoming:'我是方式2发送的数据么么哒!!'}}">点我用声明式方式2把数据给详情页</router-link>

​ (2-2)编程式:需要函数触发。

fun(){
    //了解
    this.$router.push('/all/编程式方式1')
},
funb(){
  //掌握
  this.$router.push({name:'All',params:{xiaoming:'我是编程式方式2'}})
}

(3)接收参数

​ this. r o u t e . p a r a m s . x x x 注 意 单 词 是 route.params.xxx 注意单词是 route.params.xxxroute

query

query方式千万不要在路由规则中配置接受参数

query方式千万不要在路由规则中配置接受参数

query方式千万不要在路由规则中配置接受参数

query方式千万不要在路由规则中配置接受参数

query方式千万不要在路由规则中配置接受参数

使用:

(1)发送数据

声明式

 
        
        <router-link to="/queryall?suibian='我是query声明式方式1'">query声明式方式1router-link>
        
          <router-link :to="{name:'Queryall',query:{suibian:'我是query声明式方式2呵呵哒'}}">query声明式方式2router-link>
        
          <router-link :to="{path:'/queryall',query:{suibian:'我是query声明式方式3么么哒'}}">query声明式方式3router-link>

编程式 课下自行根据ppt尝试

(2)接收数据

this. r o u t e . q u e r y . x x x x 注 意 单 词 是 route.query.xxxx 注意单词是 route.query.xxxxroute

$router 和 $route的区别

$router是VueRouter的一个对象,router的实例对象,这个对象中是一个全局的对象,他包含了所有的路由包含了许多关键的对象和属性。举例:history对象

$route是一个跳转的路由对象,每一个路由都会有一个route对象,是一个局部的对象,可以获取对应的name,path,params,query等

路由懒加载

当我们的项目体积越来越大的时候 首次页面加载可能会吧所有的路由页面渲染之后在进行显示 那么这个时候 就会造成首页渲染过慢 首页白屏 就需要使用路由懒加载技术来避免 懒加载按需加载(当你需要这个路由的时候他才会去加载这个路由页面)懒加载可以分割代码块,提高页面的初始加载效率。

常用的懒加载方式有两种:即使用vue异步组件懒加载 和 ES中的import

vue异步组件懒加载:

主要是使用了Promise.resolve()的异步机制,用require代替了import,实现按需加载
component:resolve=>(require([“引用的组件路径”],resolve))

ES中的import(推荐写法)

const HelloWorld = ()=>import(‘需要加载的模块地址’)

路由守卫/导航守卫/路由钩子/导航钩子/跳转限制

路由守卫:就是在路由跳转的时候被自动调用的一下函数 这些函数可以在我们进行路由跳转的时候多一些验证。

全局:

当一个导航触发时,全局前置守卫(在进入组件之前)按照创建顺序调用。
vue-router 提供的 router.beforeEach((to,from,next)=>{})可以方便地实现全局前置导航守卫
to:即将要进入的目标 路由对象
from: 当前导航正要离开的路由
next: 下一步执行

当一个导航触发时,全局后置钩子(在进入组件之后)调用。
vue-router 提供的 router.afterEach((to, from) => {})实现全局后置守卫
to:即将要进入的目标 路由对象
from: 当前导航正要离开的路由

路由独享:

与全局前置守卫相比路由独享守卫只是对当前路由进行单一控制参数和全局前置守卫相同

组件内:

在组件中使用beforeRouteEnter(to, from, next) {}来进行进入组建前的钩子

扩展小知识----浏览器自动开启与端口修改

在项目的根路径下根路径下根路径下根路径下创建一个文件名为vue.config.js

module.exports={
    devServer:{
        open:true, //自动开启
        port:8888//修改端口
    }
}

扩展小知识----修改更多的文件夹别名

写在vue.config.js中

module.exports={
//修改文件夹别名
    configureWebpack:{
        resolve:{
          alias:{
            // "别名":"对应的文件夹"
            "c":"@/components"
          }
        },

    devServer:{
        open:true, //自动开启
        port:8888//修改端口
    }
}
}

数据请求与模拟数据*

请求封装拦截器

1.新建util 并且创建js文件用来承载拦截器

import axios from "axios"
// 创建axios 赋值给常量service 
const service = axios.create();

// 添加请求拦截器(Interceptors)
service.interceptors.request.use(function (config) {
    // 发送请求之前做写什么
    return config;
  }, function (error) {
    // 请求错误的时候做些什么
    return Promise.reject(error);
  });

// 添加响应拦截器
service.interceptors.response.use(function (response) {
    // 对响应数据做点什么
    return response;
  }, function (error) {
    // 对响应错误做点什么
    return Promise.reject(error);
  });
  export default service

2.新建api文件夹用来存放数据请求的封装

import Service from "u/service.js"

// export default 只能暴漏一个内容

// export 可以出现多次
export function getlink(url){
        return new Promise((resolve,reject)=>{
            Service.request({
                url,
                method:"GET"
            }).then((ok)=>{
                resolve(ok)
            }).catch((err)=>{
                reject(err)
            })
        })
    }

3.在想使用的组件中进行调用

import {getlink} from "a/getapi.js" 
 mounted(){
   
        getlink("xxx").then((ok)=>{
            console.log(ok)
        })
    }

模拟数据

在项目开发之初 前台和后台开发者都是同时进行开发的 前台速度可能会快一些 那么在这个时候 后台没有办法第一时间给我们提供数据接口 这个时候就需要前台开发者自己先新建模拟数据先来开发 (后台会说你前台需要什么格式的数据?你就把你的模拟数据给他 让他安装你的模拟数据给你返回即可)

使用:

1.下载 npm install --save mockjs

2.新建容纳模拟数据的文件夹与文件 mock文件夹 index.js

3.在mock文件夹中创建模拟的j数据

4.在index.js中编写代码

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

5 在main.js中引用mock

require("./mock")

6.在请求中想怎么用就怎么用

动态组件

多个组件使用一个挂载点 并且可以动态切换




keepalive

在动态组件或者是在路由中如果我们切换路由页面或者动态组件的时候 由于每次切换都会新创建一个vue实例会导致数据的状态丢失

解决这个问题,我们可以用一个 元素将其路由出口包裹起来。在切换过程中将状态保留在内存中,防止重复渲染DOM,减少加载时间及性能消耗,提高用户体验性

使用:

​ 包裹你要保存状态的内容

keepalive属性

在vue 2.1.0 版本之后,keep-alive新加入了两个属性:

include(包含的组件缓存)

exclude(排除的组件不缓存,优先级大于include) 。

keepalive钩子函数

在keepalive的阶段内被自动调用的函数叫keepalive的钩子函数

activated 类型:func 触发时机:keep-alive所管理的组件进入的时候触发
deactivated 类型:func 触发时机:keep-alive所管理的组件离开的时候触发;

以上两个钩子函数需要写在被管理的组件中






ref

在vue中进行dom操作

可以获取DOM对象
绑定:

我是ref

获取: this.$refs.demo

ref可以绑定到dom元素上

ref绑定到组件上

因为组件是自定义标签

可以得到子组件的信息包含变量和方法

常见面试题?

父组件如何触发子组件的方法? 使用ref绑顶到组件之上就可以获取组件的信息包含方法

vuex

创建

和之前vue脚手架项目一样创建唯独就是在创建的时候 选择vuex这一项

基本概念

vuex就是状态(数据)管理工具 就是把项目中的数据集中的放到一个数据仓库中 大大减少了组件与组件之间数据传递的复杂度

vuex state属性 数据源

state: 在vuex中就是用来存放数据的

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

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    text:"我是vuex的数据text",
    num:18,
    arr:[111,2222,3333,444],
    obj:{name:"xixi",age:18}
  }
})

组件中使用数据

在想使用的组件中 直接使用 this.$store.state.xxx




vuex mutations属性 修改数据源

1.mutations就是vuex中修改数据的 他里面有多个方法 每个放法就是一个修改的动作

  // 要修改数据就要使用mutations
  mutations:{
    // 今后的修改操作有很多  那么每一个修改的动作就是一个函数
    add(){
      console.log("+++++")
    },
    del(){
      console.log("------")
    }
  }

2.在组件中调用vuex的修改mutations 要使用commit(“名字”)





实战修改

mutations的每个放法中都会有一个形参这个形参代表的就是上面的数据源

修改操作:

  mutations:{
    // 今后的修改操作有很多  那么每一个修改的动作就是一个函数
    // mutations的每个放法中都会有一个形参这个形参代表的就是上面的数据源
    add(state){
      state.num++
    },
    del(state){
      state.num--
    }
  }

payload载荷

就是可以从外部往vuex的mutations的一个个方法中传递实参

组件页面在传递调用commit的时候需要在commit(“名字”,你要传递的数据)





在vuex中需要接收 payload

mutations:{
    // 今后的修改操作有很多  那么每一个修改的动作就是一个函数
    // mutations的每个放法中都会有一个形参这个形参代表的就是上面的数据源
    add(state,payload){
      state.num+=payload
    
    },
    del(state,payload){
      state.num-=payload
    }
  }

多个参数也可以传递一个对象
this.$store.commit(‘add’, { ‘num’: 20 } )

vuex工作中遇见的问题

vuex数据刷新会丢失

  created () {
        //在页面加载时读取localStorage里的状态信息
        if (localStorage.getItem("data") ) {
            //replaceState替换数据 Object.assign合并对象
            this.$store.replaceState(Object.assign({}, this.$store.state,JSON.parse(localStorage.getItem("data"))))
        } 
        //在页面刷新时将vuex里的信息保存到localStorage里
        window.addEventListener("beforeunload",()=>{
            localStorage.setItem("data",JSON.stringify(this.$store.state))
        })
      },


vuex actions属性 操作异步

actions 用来承载异步操作 用来操作异步的 每个异步操作就是一个方法

  // 用来操作异步的  每个异步操作就是一个方法
  actions:{
    uplink(){
      console.log("我是一个异步请求")
    }
  }

调用使用dispatch

this.$store.dispatch()

 methods:{
    fun(){
      // this.$store.dispatch("actions的名字")
      this.$store.dispatch("uplink")
    }
  },

实战使用:

在actions中添加异步请求(把原来写在组件中的内容放大actions中)

// 用来操作异步的  每个异步操作就是一个方法
  actions:{
    uplink(){
      apilink("http://api.artgoer.cn:8084/artgoer/api/v1/user/324380/v3/topic/topicHomeByLabel?pageIndex=1&token=b544cd63-6d42-46fe-a96c-3cf96bae3113&topicId=62187").then((OK)=>{
        console.log(OK)
      })
    }
  }

actions中的payload

1.在dispatch(“名字”,数据)

2.使用的时候需要用payload接受

数据请求vuex的闭环操作

vuex getters属性 vuex的计算属性

是vuex的计算属性 一条数据在不同位置展示出不同的形态时候使用

 // vuex的计算属性
  getters:{
    uptitle(state){
      // 必须有return
      return state.title.toUpperCase()
    },
    strtitle(state){
      return state.title.substr(1,3)
    }
  } 

使用

this.$store.getters.xxx

vuex modules属性 把vuex拆分成一个个个模块

1.新建一个随便名字的文件夹(modules)用来存放一个个模块

2.在其中分别创建多个文件.js

3.在文件中写入state mutations actions getters

export let userm={
    state:{
        usertext:"我是user的数据"
    },
    mutations:{

    },
    actions:{

    }
}

4.把这些模块文件在store文件中 先引用 在使用

import Vue from 'vue'
import Vuex from 'vuex'
import {homem} from "./modules/homem.js"
import {userm} from "./modules/userm.js"
import {aboutm} from "./modules/aboutm.js"

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
  },
  mutations: {
  },
  actions: {
  },
  modules: {
    homem,userm,aboutm
  }
})

5.页面调用除了获取state数据有区别 剩下的调用commit修改 dispatch异步操作和原来一样

state变成了: this.$store.state.模块名.xxx

总结一些流程

dispatch调用actions进行异步请求 把请求来的数据通过commit调用mutations进行state的数据修改 从而在页面中展示

modules是一个模块用来拆分vuex的复杂度

getters是vuex的计算属性 一条数据在不同组件位置展示出不同的形态使用

跨域

为什么跨域?

因为浏览器的安全机制 同源策略( 同端口 同协议 同域名 )

1.jsonp 动态创建一个script标签

2.代理跨域

因为vue脚手架中集成了一个小的内置服务器叫devServer 我们代理跨域就是让这个小的内置服务器帮助我们请求数据 这样一来我们就绕开了浏览器同时也就绕开了浏览器的安全机制—同源策略

1.配置代理跨域在vue.config.js中的devServer中配置如下内容

module.exports={
    devServer:{
        open:true,
        proxy: {
            '/api': {
              target: 'http://www.weather.com.cn/', //对应自己的接口
              changeOrigin: true,
              ws: true,
              pathRewrite: {
                '^/api': ''
              }}
             }

    }
}

2,千万不要忘了去修改你的请求地址

3.cors(后端解决)

工作小问题

在公司跨域谁解决?

1.在开发过程中 通常前端解决(代理跨域 上线之后就废了)

2.上线之后肯定是后端解决

axios发送数据

get

​ 使用params发送数据 params需要一个对象

import service from "@/util/service.js"

export function getlink(url,params){
    return new Promise((resolve)=>{
        service.request({
            url,
            method:"GET",
            // 发送数据
            params
        }).then((ok)=>{
            resolve(ok)
        })
    })
}

发送的时候

    getlink("地址",{数据}).then((ok)=>{
        console.log(ok)
      })

post

使用post发送数据需要使用 var param=new URLSearchParams();修改传参方法
使用param.append(“uname”,“xixi”)添加数据并且使用data发送数据

import service from "@/util/service.js"

export function postlink(url,data){
    return new Promise((resolve)=>{
        service.request({
            url,
            method:"POST",
            data
        }).then((ok)=>{
            resolve(ok)
        })
    })
}
funb(){
      let usp=new URLSearchParams
      // usp.append("key","val")
      usp.append("posttext",this.inputvalb)


      postlink("/api/ceshi/post",usp).then((ok)=>{
        console.log(ok)
      })
    }

vantui

https://vant-contrib.gitee.io/vant/#/zh-CN/

自定义指令

指令 就是在vue中v-前缀的html特殊属性

指令 是有限的就那几个 但是如果我想用的功能没有的怎么办?

自定义指令--------- 就是我们自己定义指令

5个钩子要记住

5个钩子要记住

5个钩子要记住

5个钩子要记住

5个钩子要记住

5个钩子要记住





混入 mixins

就是在vue组件的风格不同(就是显示的内容不一样)同时在多个组件中有一些相同的属性和方法显然我们不能在每个组件里面都写一遍 我们需要那这些相同的内容提取出来 写成一个公共的 那么这个公共的文件就叫mixins

局部混入

创建混入文件

let myMixins={
    data(){
        return {
            text:"呵呵"
        }
    },
 methods:{
        fun(){
            alert("你好")
        }
    },
    directives:{
        xiaoming:{
            inserted(el){
                el.style.backgroundColor="red"
            }
        }
    }
}

// 不要忘了暴露
export default myMixins

使用混入 用mixins属性对应一个数组






全局混入

在任何组件中都可以使用
在main中引用 并且使用
import MinXin from ‘@/components/MinXins/index.js’
Vue.mixin(MinXin);

在组件中即可随意使用混入中的数据

组件传值

正向传值

props

逆向传值

通过事件触发一个$emit()

父组件怎么直接触发子组件的方法?

使用ref绑定到子组件之上

同胞传值

1.愚蠢的方式

先逆向传值给父组件 父组件在正向传值给子组件

2.中央事件总线方式

创建一个新的Vue实例,以后它就承担起了组件之间通信的桥梁了,也就是中央事件总线。

1、创建一个事件总线,例如demo中的eventBus,用它作为通信桥梁

2、在需要传值的组件中用bus.emit触发一个自定义事件,并传递参数(emit前加美元符)

3、在需要接收数据的组件中用bus.$on监听自定义事件,并在回调函数中处理传递过来的参数

跨层级传值

vuex

$set

你在vue开发中有没有遇见过 模型数据改变了 但是视图没有发生改变的情况 是怎么解决这个问题的?

出现的场景

当vue的data里边声明或者已经赋值过的对象或者数组(数组里边的值是对象)时,向对象中添加新的属性,如果更新此属性的值,是不会更新视图的。








出现这种情况的原理

官方这样说:

当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。
受现代 JavaScript 的限制 (以及废弃 Object.observe),Vue 不能检测到对象属性的添加或删除。由于 Vue 会在初始化实例时对属性执行 getter/setter 转化过程,所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的。

简单点来解释:

Object.defineProperty只会在初始化的时候监听data模型数据 如果中途加入新的对象属性 那么这个方法就不会监听到 不监听也就没有了双向绑定 没有了双向绑定就不会有模型变了视图发生改变这一说

解决问题

$set()








nextTick

vue的数据修改之后视图是立即更新吗?

Vue 在修改数据后,视图不会立刻更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图更新。

vue.nexttick 等待 Vue 完成更新 DOM 可以在数据变化之后立即调用

vue.nexttick 等待 Vue 完成更新 DOM 可以在数据变化之后立即调用

vue.nexttick 等待 Vue 完成更新 DOM 可以在数据变化之后立即调用

vue.nexttick 等待 Vue 完成更新 DOM 可以在数据变化之后立即调用

vue.nexttick 等待 Vue 完成更新 DOM 可以在数据变化之后立即调用****






原理:

1.首先修改数据,这是同步任务。同一事件循环的所有的同步任务都在主线程上执行,形成一个执行栈,此时还未涉及DOM.
2.Vue开启一个异步队列,并缓冲在此事件循环中发生的所有数据变化。
3.同步任务执行完毕,开始执行异步队列的任务,更新DOM

打包上线

npm run build 进行打包

在项目下面会生成一个dist文件夹就是打包好的内容 运行其中的html文件即可

运行之后会发现白屏 在控制台会发现有报错

需要修改静态资源路径

在vue.config.js中 添加publicPath:"./"设置为当前级、

module.exports={
    publicPath:"./"
}

下面的是完整配置 (每个公司的需求都不同 所以这个配置不是固定的 百分之99的公司都没有这么多的需求)

module.exports = {
   
    // 基本路径
    publicPath: './', //部署应用包时的基本 URL
    runtimeCompiler: false, //是否使用包含运行时编译器的 Vue 构建版本。设置为true可以使用template
    productionSourceMap: false,//生产环境是否生成 sourceMap 文件
    lintOnSave: true,
    chainWebpack(config) {
        config.resolve.alias
        //     .set('style', resolve('public/style'))
        config.output.filename('js/[name].[hash:16].js');//hash值设置
        config.output.chunkFilename('js/[id].[hash:16].js');
        // config.output.filename('css/[name].[hash:16].css');//hash值设置
    },
    configureWebpack: () => {
    },
    // css相关配置
    css: {
        // 是否使用css分离插件 ExtractTextPlugin
        extract: true,
        // 开启 CSS source maps?
        sourceMap: false,
        // css预设器配置项
        loaderOptions: {},
        // 启用 CSS modules for all css / pre-processor files.
        modules: false
    },
    parallel: require('os').cpus().length > 1,//是否为 Babel 或 TypeScript 使用 thread-loader
    // PWA 插件相关配置
    // see https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa
    pwa: {},
    // webpack-dev-server 相关配置
    devServer: {
        
   
        port: 8888,
        https: false,
        hotOnly: false,
        // 设置代理
        proxy: {
            '/api': {
              target: 'http://localhost:3000/', //对应自己的接口
              changeOrigin: true,
              ws: true,
              pathRewrite: {
                '^/api': ''
              }
            }
          }, 
       
    },
    // 第三方插件配置
    pluginOptions: {
        // ...
    }
}

在打包运行发现什么都没有 也没有报错

解决:把路由模式修改成hash

在打包运行即可

组件的二次封装

1ui组件的部分样式不满足当前项目的需求。

2.ui组件出现问题的时候,我们有中间键支持,不至于整个项目崩塌。

二次封装的弊端:

因为我们对element-ui进行了二次封装,当element-ui组件升级的时候,我们二次封装的组件不能直接使用element-ui的新方法,所以需要有人不断的对组件进行维护,有一定的开发成本。

如何对element对进行二次封装?

创建组件并且把elementui 指定的内容放置其中 (可以吧需要的参数定义成props方便复用)

在main.js中进行引用当前封装的组件 并且使用Vue.component(“组件名”,引用的组件) 设置成全局组件

新建layout文件夹 并且 在内部新建指定存放的文件夹

如果需要组件功能复用 那么可以使用传值方式进行参数的传递

Vue路由扩展

页面中使用:this.$route.meta.xxx

页面中得到路由信息

this.$router.options.routes

你可能感兴趣的:(vue,前端,vue,node.js)