# Vue 笔记

# 基本概念

# 后端渲染 后端路由

  • 后端渲染:由后端处理将渲染好的 HTML 页面并发送给客户端
  • 后端路由:由后端处理 URL 和页面之间的映射关系

# 前后端分离

  • 前后端分离:后端只负责提供数据
  • 前端渲染:浏览器中显示的网页中的大部分内容,都是由前端写的 js 代码在浏览器中执行,最终渲染出来的网页

# 单页面富应用(SPA)

单页面富应用(SPA)整个页面只有一个 HTML,所有页面都在里面(依次隐藏显示) 前端路由:URL 与 HTML 页面间的映射关系

# 命令式编程和函数式编程

  • 命令式编程:一步一步命令
  • 函数式编程:先拿到数据,然后再处理

# Vue 响应式原理

  1. app.message 修改数据,Vue 是如何监听 message 数据的改变
  • object.defineProperty -> 监听对象属性的改变
  1. 当数据发生改变,Vue 是如何知道要通知哪些人,界面发生刷新

响应式原理

# Visual Studio Code 插件

  • Vue

# 浏览器插件

  • vuejs-devtools

# 脚手架

脚手架让项目从搭建到开发,再到部署,整个流程变得快速和便捷

编程中提到的脚手架 (Scaffold) , 其实是一种工具,帮我们可以快速生成项目的工程化结构,并且已经将我们所需的工程环境配置好

  • 每个项目作出完成的效果不同,但是它们的基本工程化结构是相似的。既然相似,就没有必要每次都从零开始搭建,完全可以使用一些工具,帮助我们生产基本的工程化模板
  • 不同的项目,在这个模板的基础之上进行项目开发或者进行一些配置的简单修改即可
  • 这样也可以间接保证项目的基本机构一致性,方便后期的维护

# 依赖

  1. 安装 Node.js:Node.js 官网 (opens new window)
  2. 安装 WebPack:npm install webpack -g

# 安装

安装 Vue 脚手架:npm install @vue/cli -g

# 创建项目

  • 可视化创建项目: vue ui

  • 命令行创建项目:vue create 项目名称

    • Router:路由
    • Unit Tests:单元测试
    • Linter / Formatter:Eslint 代码规范检测
    • 推荐选择 Runtime-only(性能更好,所使用的代码量更少)
    • 推荐选择dist-sassnode-sass编译缓慢

# 启动项目

启动项目:npm run serve

# 编译项目

编译项目:npm run build

# 项目结构

  • node_modules: 依赖文件目录
  • .gitignore: 记录 git 版本控制的排除文件
  • package.json: 记录各个依赖的版本(^表示可小版本迭代更新)
  • package-lock.json: 记录本地真实安装版本

# 关闭 Eslint 代码规范检测

\config\index.js

useEslint: false;

# 配置目录别名

新建文件 项目目录\vue.config.js

module.exports = {
  configureWebpack: {
    resolve: {
      alias: {
        assets: "@/assets",
        components: "@/components",
        views: "@/views",
      },
    },
  },
};

提示

不用配置routerstore,因为可以全局访问

# 解决 build 后打开空白问题

新建 vue.config.js,内容:

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

# 解决 build 后路由跳转 404

取消 history

index.js

const router = new VueRouter({
  //mode: 'history',
});

# 基本语法

# v-for

v-for 为循环,后接表达式:变量 in 列表

<ul>
  <li v-for="item in textlist">{{item}}</li>
</ul>

绑定 key 用于更高效的更新虚拟 DOM 渲染 注意:key 不能重复,不能用 index

<ul>
  <li v-for="item in textlist" :key="item">{{item}}</li>
</ul>
<!--在遍历的过程中获取索引值-->
<ul>
  <li v-for="(item,index) in textlist">{{index+1}}:{{item}}</li>
</ul>
<!--获取key和value 格式:(value,key)-->
<ul>
  <li v-for="(value,key) in info">{{key}}:{{value}}</li>
</ul>
<!--获取key和value 格式:(value,key)-->
<ul>
  <li v-for="(value,key,index) in info">{{key}}:{{value}},{{index}}</li>
</ul>

# @click (v-on)

事件绑定,后接表达式:命令
获取 event 事件对象:$eveut

<button @click="事件方法()">按钮</button>
<button v-on:click="事件方法()">按钮</button>

# prevent 修饰符

prevent 修饰符,用于阻止默认程序事件

<form>
  <input type="submit" value="提交" @click.prevent="btnClick()">
</form>

# @keyup

监听键盘的按键

<input type="txt" @keyup="keyup()">
<input type="txt" @keyup.enter="keyup()">

# v-model

双向绑定数据,后接双向绑定的变量

<input type="text" v-model="message">

# v-bind

# 动态绑定属性

v-bind 用于动态绑定属性,例如图片等 (双大括号无效)

简写:

<a :href="url2">v-bind简写测试</a>

普通写法:

<a v-bind:href="url2">v-bind测试</a>

# 动态绑定样式

<h2 :style="{属性: '',属性: 值}"></h2>
<h2 :style="{fontSize: '50px',color: color}"></h2>

提示

属性值注意增加单引号,否则会解析为变量

# 动态绑定 class

后接表达式:{属性名 : 属性值}

<!-- 传入对象 -->
<h2 v-bind:class="{类名 : 布尔值}"></h2>
<!-- 传入数组 -->
<h2 v-bind:class="[类名1,类名2]"></h2>
<!-- 对象、数组混用 -->
<h2 v-bind:class="[{类名 : 布尔值},类名]"></h2>
<!--传入函数 -->
<h2 v-bind:class="getclass()"></h2>
getclass() {
  return {
    类名1: 布尔值,
    类名2: 布尔值,
  }
}

# v-html

v-html 为解析 HTML,后接 html 字符串

<h1 v-html="url"></h1>

# v-once

v-once 为只渲染一次,不随数据的改变而改变

<h1 v-once>{{message}}</h1>

# v-pre

v-pre 为不解析,原封不动的显示出来

<h1 v-pre>{{message}}</h1>

# v-if

用于控制显现/隐藏,true 为显现,false 为隐藏

<h2 v-if="true">{{message}}</h2>
<!--v-else与v-if的值相反,当v-if为false时v-else则显示-->
<h2 v-else>{{message}}</h2>

提示

此方法是完全隐藏,不显示在 dom 中,适合切换频率低的环境

# v-show

v-show 用于控制显现/隐藏,true 为显现,false 为隐藏

<h2 v-show="true">{{message}}</h2>

提示

只是给元素增加 display:none,适合切换频率高的环境

# v-load

v-load 用于监听图片是否加载完成

<img :src="" @load="事件名称">
export default {
  methods: {
    事件名称(){

    },
  }
},

# 过滤器

{{变量名 | 过滤器名}}
export default {
  filters: {
    过滤器名(value){
      return value;
    }
  },
}

# nextTick 函数

nextTick 函数是待所有 DOM 组件创建完成后执行的回调函数,此时$ref 等可以直接使用

export default {
  created() {
  this.$nextTick(()=>{

  })
  }
}

# 组件

提示

<style scoped></style>中的 scoped 表示编写的样式是局部有效

# 创建组件

.Vue

<template>
  <div>

  </div>
</template>

<style scoped>
</style>

<script>
  export default {
    name: '',
    //传参:父传子,写法:["形参1"[,"形参2"]]
    props: {

    },
    created(){

    },
    mounted(){

    },
    data(){
      return {

      }
    },
    methods: {

    },
    mixins: [],
    components: {

    },
  }
</script>

提示

<style scoped></style> 中的 scoped 表示作用域,不予其他 CSS 样式相冲突

# 注册组件

import 组件名称 from '@/components/组件路径名称'

export default {
components: {
  组件名称,
},

# 使用组件

<组件名称></组件名称>

# 组件传参

  • 父传子

    export default {
      //传参:父传子,写法:["形参1"[,"形参2"]]
      props: ["参数1", "参数2"],
      //限制数据类型传参
        props: {
        参数1: Array,
        参数2: String,
        },
      /*
      支持验证以下类型:
      String
      Number
      Boolean
      Array
      Object
      Date
      Function
      Symbol
      */
    }
    
    <组件 参数1="" [参数2=""]...></组件>
    
  • 子传父

    export default {
      template: "#cpn",
      methods: {
        btnClick([参数]){
          //发射事件:自定义事件
          this.$emit("事件名称" [,参数])
        }
      },
    }
    
    <组件 @事件名称="事件方法()"></组件>
    

提示

如提示$emit不是一个函数则将父函数写为箭头函数

# 组件事件

<组件 @click.native="事件方法()"></组件>

提示

native 修饰符用于监听组件根元素的原生组件

# 混入

混入是对重复代码进行封装,与组件类似。但是混入后的组件可之间访问变量(相当于合并代码)

# 声明

mixin.js

import 组件名称 from 'components/组件名称'

export const 混入名称 = {
  created(){

  },
  mounted(){

  },
  data() {
    return {

    }
  },
  methods:{

  },
  components: {
    组件名称,
  }
}

# 使用

<组件名称></组件名称>
import { 混入名称 } from 'common/mixin'

export default {
  //混入
  mixins: [混入名称],
}

# 插槽

在开发中,我们抽取了一个组件,但是为了让这个组件具备更强的通用性,我们不能将组件中的内容限制为固定的 div、span 等等这些元素,我们应该让使用者可以决定某一块区域到底存放什么内容。

举栗:假如我们定制一个通用的导航组件 - NavBar

  • 这个组件分成三块区域:左边 - 中间 - 右边,每块区域的内容是不固定
  • 左边区域可能显示一个菜单图标,也可能显示一个返回按钮,可能什么都不显示
  • 中间区域可能显示一个搜索框,也可能是一个列表,也可能是一个标题,等等
  • 右边可能是一个文字,也可能是一个图标,也可能什么都不显示
<template>
<div>
  <slot name="插槽名称"><span>插槽</span></slot>
</div>
</template>
<组件>
  <template v-slot:插槽名称>
    <h2>这是left插槽</h2>
  </template>
</组件>

# 绑定元素

<div ref="元素标识"></div>
this.$ref.元素标识;

提示

  • ref 如果是绑定在组件中的,那么通过this.$refs.refname获取到的是一个组件对象;
  • ref 如果是绑定在普通的元素中,那么通过this.$refs.refname获取到的是一个元素对象。

# 防抖函数

触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
效果:短时间内多次触发同个事件,只会执行一次函数。

  • 实现

    /**
     * @param {Function} 欲防抖函数
     * @param {number} 防抖时间
     * @return {Function} 防抖函数
     */
    function debounce(func, delay){
      let timer = null;
      return function(...args){
        if(timer) clearTimeout(timer);
        timer = setTimeout(()=>func.apply(this,args), delay);
      }
    }
    
  • 使用

    提示

    需要进行防抖处理的函数名称不能加入(),否则会识别为函数的返回值

    const log = debounce(console.log, 100);
    log('Hello'); // 取消执行
    log('Hello'); // 取消执行
    log('Hello'); // 在100ms时执行
    

# 节流函数

连续触发事件但是在 n 秒中只执行一次函数,所以节流稀释了函数执行的频率。 效果:n秒内多次触发同个事件,只会执行一次函数,直到下一个n秒才会重新生效。

  • 实现

    /**
     * @param {Function} 欲节流函数
     * @param {number} 节流时间
     * @return {Function} 节流函数
     */
    function throttle(fn, t) {
      // 正在运行的函数启动时间
      let start
      // 等待运行存储最新的函数
      let timer
      return function(...args) {
          // 调用函数当前时间
          let now = new Date();
          // 当前函数没有启动过start为undefined,则可以立即启动
          if (!start) {
              // 存储函数的启动时间
              start = new Date();
              fn.apply(this, args);
          } else if (now - start >= t) { // 超过tms间隔则可以立即运行
              start = new Date()
              fn.apply(this, args)
          } else {   // 没有超过tms则需要存储函数,等tms结束后立即运行
              clearTimeout(timer)
              timer = setTimeout(() => {
                  start = new Date();
                  fn.apply(this, args);
              }, t - (now - start));
          /* now-start: 距离tms已经过了多久,t-(now-start): 还需要等待多久才能运行 */
          }
      }
    }
    
  • 使用

    const throttled = throttle(console.log, 100);
    throttled("log"); // 立即执行
    throttled("log"); // 在100ms时执行
    

# 常用组件使用实例

# 单选框

<input type="radio" id="male" name="sev" value="" v-model="sex"><input type="radio" id="female" name="sev" value="" v-model="sex"><br>
<h2>{{sex}}</h2>

# 多选框

<!--label标签作用:点击文字也能触发检查框-->
<label><input type="checkbox" id="agree" v-model="isagerr">同意协议</label>
<button :disabled="!isagerr">下一步</button>

<input type="checkbox" value="测试选项1" v-model="totalcheckbox">测试选项1
<input type="checkbox" value="测试选项2" v-model="totalcheckbox">测试选项2

<label v-for="item in totealselect">
<input type="checkbox" :value="item" v-model="totalcheckbox">{{item}}
</label>

# 下拉选择框

<select v-model="selectvalue">
  <option>测试选项1</option>
  <option>测试选项2</option>
</select>

# HTML-Vue 模板

点击查看代码
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vue</title>
  </head>
  <body>
    <div id="app">
      <h1>{{message}}</h1>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>
    app = new Vue({
      //声明要绑定的id
      el: '#app',
      //页面加载完毕后执行的方法(渲染前)
      created(){

      },
      //页面加载完毕后执行的方法(渲染后)
      mounted(){

      },
      //数据对象
      data: {

      },
      //计算属性:属性名称(){} (调用时不需要加小括号)
      computed: {

      },
      //定义方法:方法名称(){}
      //当前对象内需要加this
      methods: {

      },
    })
    </script>
  </body>
</html>
最后更新: 2023/6/25 10:37:51