前端学习笔记(五):VUE基础学习笔记

初识VUE(项目搭建)

VUE渐进式javacript框架, 一套拥有自己规则的语法,官网地址: https://cn.vuejs.org/,渐进式: 逐渐进步, 想用什么就用什么, 不必全都使用。库是方法的集合, 而框架是一套拥有自己规则的语法。

  1. Vue推荐采用.vue文件来开发项目
    ⚫ template里只能有一个根标签,什么标签都行,但是只能有一个
    ⚫ vue文件-独立模块-作用域互不影响
    ⚫ style配合scoped属性, 保证样式只针对当前template内标签生效
    ⚫ vue文件配合webpack, 把他们打包起来插入到index.html
@vue/cli 创建项目

@vue/cli是Vue官方提供的一个全局模块包(得到vue命令), 此包用于创建脚手架项目.脚手架里面已经帮我们配置好了webpack

  1. yarn global add @vue/cli / npm install @vue/cli –g 进行安装,全局包会在计算机中配置全局命令(例: vue命令)
  2. vue -V 可以查看安装的版本
  3. 创建项目 vue create 项目名 项目名不能有大写字母, 中文和特殊符号
  4. 进入到项目目录下 yarn serve 启动项目
  5. 生成的项目,各个文件代表的含义总结如下:
    在这里插入图片描述

main.js 打包了APP.vue,然后又把相关的内容放到了index.html上让我们看到。
6. 关系总结如下:
在这里插入图片描述

@vue/cli 自定义配置
  1. 例如我们想要修改端口号这样的需求,需要在src并列处新建vue.config.js, 填入配置, 重启webpack开发服务器。项目中没有webpack.config.js文件,因为Vue脚手架项目用的vue.config.js。
  2. 关闭代码检查工具:eslint是一种代码检查的工具,如果写代码违反了eslint的规则-报错,暂时关闭eslint检查, 在vue.config.js中配置后重启服务:
module.exports = {
    // ...其他配置
    lintOnSave: false // 关闭eslint检查
}

3.vue报错示例:
在这里插入图片描述

vue指令

基础指令
  1. 变量同一放在data函数的return里面(固定写法)。然后再标签里面使用{{ }}将变量插入到里面。
export default {
 data(){
    return {
      count: 1
    }
  },
  // 2. 定义函数
  methods: {
    addFn(){ // this代表export default后{}对象, data和methods里的属性都直接挂在它身上
      this.count++
    },
  }
}
  1. MVVM设计模式:设计模式: 是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结,MVVM(模型, 视图, 视图模型双向关联的一种设计模式),减少DOM操作, 提高开发效率
  2. 指令给标签添加额外的功能,将变量值绑定给标签的属性,语法: v-bind:属性名=“vue变量”。简写: :属性名="vue变量
  3. 给标签绑定事件,v-on: 可以简写成@:
    ⚫ v-on:事件名=“要执行的少量代码"
    ⚫ v-on:事件名=“methods中的函数名"
    ⚫ v-on:事件名=“methods中的函数名(实参)"
  4. 获取事件对象:
    ⚫ 无传参, 通过形参直接接收
    ⚫ 传参, 通过$event指代事件对象传给事件处理函数
<template>
  <div>
    <a @click="one" href="http://www.baidu.com">百度</a>
    <hr />
    <a @click="two(10, $event)" href="http://www.taobao.com">淘宝</a>
  </div>
</template>

<script>
export default {
  methods: {
    // 1. 事件触发, 无传值, 可以直接获取事件对象是
    one(e){
      e.preventDefault()
    },
    // 2. 事件触发, 传值, 需要手动传入$event
    two(num, e){
      e.preventDefault()
    }
  }
};
</script>
  1. 在事件后面.修饰符名 :@事件名.修饰符=“methods里函数”
    ⚫ .stop - 阻止事件冒泡
    ⚫ .prevent - 阻止默认行为
    ⚫ .once - 程序运行期间, 只触发一次事件处理函数(第一次后事件还会触发,只是函数不再执行)
  2. 检测按键的方法:
    @keyup.enter=“methods里函数” - 监测回车按键
    @keyup.esc =“methods里函数”- 监测返回按键
    更多修饰符: https://cn.vuejs.org/v2/guide/events.html
  3. 案例:
    将字符串变为数组 let arr = string.split(“”)
    然后再进行拼接 msg = arr.join(“”)
  4. v-model 双向数据绑定 。value属性 - vue变量,详细用法如下,v-model:
 <div>
      <span>来自于: </span>
      <!-- 下拉菜单要绑定在select上 -->
      <select v-model="from">
        <option value="北京市">北京</option>
        <option value="南京市">南京</option>
        <option value="天津市">天津</option>
      </select>
 </div>
<div>
      <!-- (重要)
      遇到复选框, v-model的变量值,正常情况下我们需要把变量定义为数组
      非数组 - 关联的是复选框的checked属性
      数组   - 关联的是复选框的value属性
       -->
      <span>爱好: </span>
      <input type="checkbox" v-model="hobby" value="抽烟">抽烟
      <input type="checkbox" v-model="hobby" value="喝酒">喝酒
      <input type="checkbox" v-model="hobby" value="写代码">写代码
    </div>
    <div>
      <span>性别: </span>
      <input type="radio" value="男" name="sex" v-model="gender"><input type="radio" value="女" name="sex" v-model="gender"></div>
    <div>
      <span>自我介绍</span>
      <textarea v-model="intro"></textarea>
    </div>
  </div>
  1. 语法: v-model.修饰符=“Vue数据变量”
    ⚫ .number 以parseFloat转成数字类型,如果不是数字则不进行转换
    ⚫ .trim 去除首尾空白字符
    ⚫ .lazy 在change时触发而非inupt时(失去焦点的时候在进行赋值)
  2. v-text=“Vue数据变量” v-html=“Vue数据变量” 注意: 会覆盖插值表达式
  3. 控制标签的隐藏或出现, 语法: v-show=“Vue变量” 或者 v-if=“Vue变量”
    v-show 用的display:none隐藏 (频繁切换使用)。 v-if 直接从DOM树上移除
    高级用法:
  <!-- v-if和v-else使用 -->
     <p v-if="age >= 18">成年了</p>
     <p v-else>未成年</p>
  1. 列表渲染, 所在标签结构, 按照数据数量, 循环生成,v-for=“(值变量, 索引变量) in 目标结构” 或者 v-for="值变量 in 目标结构,循环谁就加在谁身上,可以遍历数组 / 对象 / 数字 / 字符串 (可遍历结构)。v-for的临时变量名不能用到v-for范围外举例如下:
 <div>
    <!-- 语法1:
      v-for="(值变量名, 索引变量名) in 目标结构"
      口诀: 想要谁循环就放到谁身上
     -->
    <ul>
      <li v-for="(item, index) in arr" :key="index">
        {{ item }} ---- {{ index }}
      </li>
    </ul>
    
    <!-- 语法2:
      v-for="值变量名 in 目标结构"
      -->
    <ul>
      <li v-for="obj in stuArr" :key="obj.id">
        <span>{{ obj.name }}</span>
        <span>{{ obj.sex }}</span>
        <span>{{ obj.hobby }}</span>
      </li>
    </ul>
    <!-- 语法3:(了解)
      v-for="(value, key) in 对象"
       -->
    <div>
      <p v-for="(value, key) in tObj" :key="value">
        <span>{{ value }}</span>
        =======
        <span>{{ key }}</span>
      </p>
    </div>
    <!-- 语法4: (了解)
      v-for="变量名 in 固定数字"1开始遍历
     -->
    <div v-for="n in count" :key="n">{{ n }}</div>
  </div>
  1. js中需要导入图片文件(不能使用图片路径),改为变量,而在css/标签中可以直接使用图片路径,数组的方法如果能够改变数组,那么v-for也会进行改变。如果只是单纯赋值,则不会发生改变,但可以使用this.$set(参数1: 更新目标结构,参数2: 更新位置,参数3: 更新值),也可以把修改过后的数值重新赋值给原来的数组变量进行更新修改。
  2. 动态添加类名和动态添加样式
    语法 :class=“{类名: 布尔值}” 当bool值为true的时候才有这个类名
    :style=“{css属性名: 值}” 给标签添加css样式
    yarn add bootstrap可以直接下载样式,但是还是记得在main.js中引入
虚拟DOM与key
  1. template标签转给虚拟DOM(本质就是一个JS对象, 保存DOM关键信息),再转为真实DOM,方面后续更改(同级比较-根元素不变-属性改变更新属性,)。
  2. 没有key属性:最大限度重用。
    有key属性, 基于key的来比较新旧虚拟DOM, 移除key不存在元素,key要求是唯一不重复的字符串或者数值
  3. 如果key是索引,那么还是就地更新,但是,如果key是id就会根据id进行更新,有id用id, 无id用索引,key主要是配合虚拟DOM提高更新的性能。
过滤器
  1. 转换格式, 过滤器就是一个函数, 传入值返回处理后的值,想要把数据转为另一种的形式,过滤器只能用在, 插值表达式和v-bind动态属性里
  2. 语法:
    Vue.filter(“过滤器名”, (值) => {return “返回处理后的值”})
    filters: {过滤器名字: (值) => {return “返回处理后的值”}
  3. 如果定义在了main.js 文件里面,那么是全局的过滤器,使用上述的第一种写法,如果放在对应文件的export default 里面,和data同级别,那么就是局部的过滤器。
  4. 可以在属性中使用,也可以在标签中使用如:
 <p>使用翻转过滤器: {{ msg | reverse }}</p>
 <p :title="msg | toUp">鼠标长停</p>
  1. 过滤器传参: vue变量 | 过滤器(实参),对应的 filters: {过滤器名字: (值,参数) => {return “返回处理后的值”}**
  2. 多个过滤器的使用 : vue变量 | 过滤器1 | 过滤器2
  3. 注意过滤器不写参数的时候,默认会有一个要处理数据的值,不需要在使用的时候额外把这个数据传过来,但接收的时候要有一个参数
计算属性
  1. 一个变量的值, 依赖另外一些数据计算而来的结果,计算属性也是vue数据变量, 所以不要和data里重名
 <div>
    <p>{{ num }}</p>
  </div>

//与data同级别
export default {
  data(){
    return {
      a: 10,
      b: 20
    }
  },
 // 注意: 计算属性和data属性都是变量-不能重名
 // 注意2: 函数内变量变化, 会自动重新计算结果返回
  computed: {
    num(){
      return this.a + this.b
    }
  }
}
  1. 计算属性, 基于依赖项的值进行缓存,依赖的变量不变, 都直接从缓存取结果,如果值改变,函数自动执行并重新缓存。因此多次调用可能只执行一次,但是如果函数的话,调用一次就会执行一次。
  2. 若想给计算属性赋值,实现计算属性的双向绑定,需要使用计算属性的完整写法:
<div>
          <span>姓名:</span>
          <input type="text" v-model="full">
</div>

export default {
    computed: {
        full: {
            // 给full赋值触发set方法
            set(val){
                console.log(val)
            },
            // 使用full的值触发get方法
            get(){
                return "无名氏"
            }
        }
    }
}
侦听器
  1. 目标: 可以侦听data/computed属性值的改变
 /* 语法:
    watch: {
      变量名 (newVal, oldVal){
        // 变量名对应值改变这里自动触发
      }
    }
  */
  watch: {
    // newVal: 当前最新值
    // oldVal: 上一刻值
    name(newVal, oldVal){
      console.log(newVal, oldVal);
    }
  }
  1. 如果想要侦听对象值的变化,使用下面的写法:
/*语法:
      对象名: {
        handler(newVal, oldVal){

        },
        deep: true, // 深度侦听(对象里面层的值改变)
        immediate: true // 立即侦听(网页打开handler执行一次)
      }
    }
  */
  watch: {
    user: {
      handler(newVal, oldVal){
        // user里的对象
        console.log(newVal, oldVal);
      },
      deep: true,
      immediate: true
    }
  }

VUE组件

组件是可复用的 Vue 实例, 封装标签, 样式和JS代码。组件化 :封装的思想,把页面上可重用的部分封装为 组件,从而方便项目的 开发 和 维护。 一个页面, 可以拆分成一个个组件,一个组件就是一个整体, 每个组件可以有自己独立的 结构 样式 和 行为(html,css和js)

创建使用
  1. 全局注册 – main.js中 ,定义组件时最好都以大写字母开头
main.js:
import 组件对象 from 'vue文件路径'
Vue.component("组件名",组件对象)

使用的时候:
直接<组件名></组件名>
  1. 局部注册:
// 1. 创建组件 - 文件名.vue
// 2. 引入组件
import Pannel from './components/Pannel_1'
export default {
  // 3. 局部 - 注册组件
  /*
    语法: 
    components: {
      "组件名": 组件对象
    }
  */
  components: {
    PannelL: Pannel
    //如果同名可以简写成一个即可
  }
}

使用:
<PannelL></PannelL>
  1. 给style上添加scoped,可以使得Vue组件内样式, 只针对当前组件内标签生效,其会自动给标签添加data-v-hash值属性,所有选择都带属性选择,便于和其他进行区分。
组件通信
  1. 父向子传值:被引入的谁是子(如app引入了compoents,则app是父),从父亲写数据传给儿子,让儿子动态生成不一样的数据
 <!-- 
      目标: (App.vue) -> (MyProduct.vue) 分别传值进入
      需求: 每次组件显示不同的数据信息
      步骤(口诀):
        1. 子组件 - props - 变量 (准备接收)
        2. 父组件 - 传值进去
     -->
子文件:
<template>
  <div class="my-product">
    <h3>标题: {{ title }}</h3>
    <p>价格: {{ price }}</p>
    <p>{{ intro }}</p>
  </div>
</template>

<script>
export default {
  props: ['title', 'price', 'intro']
}
</script>

父亲文件:
<template>
  <div>
    <MyProduct v-for="obj in list" :key="obj.id"
    :title="obj.proname"
    :price="obj.proprice"
    :intro="obj.info"
    ></MyProduct>
  </div>
</template>

<script>
// 目标: 循环使用组件-分别传入数据
// 1. 创建组件
// 2. 引入组件
import MyProduct from './components/MyProduct'
export default {
  data() {
    return {
      list: [
        {
          id: 1,
          proname: "超级好吃的棒棒糖",
          proprice: 18.8,
          info: "开业大酬宾, 全场8折",
        },
        {
          id: 2,
          proname: "超级好吃的大鸡腿",
          proprice: 34.2,
          info: "好吃不腻, 快来买啊",
        },
        {
          id: 3,
          proname: "超级无敌的冰激凌",
          proprice: 14.2,
          info: "炎热的夏天, 来个冰激凌了",
        },
      ],
    };
  },
  // 3. 注册组件
  components: {
    // MyProduct: MyProduct
    MyProduct
  }
};
</script>
  1. 最好不要再子组件中改父组件传过来的值,而且本身props定义的变量本身就是只读的。从父到子的数据流向, 叫单向数据流
  2. 子向父亲传值
    (1)父组件内, 绑定自定义事件和事件处理函数 语法: @自定义事件名=“父methods里函数名”,注意只需要函数名,如果有参数也不需要,因为参数是子组件传过来的
    (2)子组件内, 触发父给我绑的自定义事件, 导致父methods里事件处理函数执行,使用this.$emit(‘父组件自定义的事件名’,传入的参数)
  3. 兄弟组件之间传递值:首先创建一个空白对象并且导出,然后再两个组件中进行导入,并传值:
    在这里插入图片描述
空白组件/index.js://注意名字,通常是eventBus文件夹
import Vue from 'vue'
// 导出空白vue对象
export default new Vue()

传值文件:
import eventBus from '../EventBus'
export default {
  methods: {
    subFn(){
      eventBus.$emit("send", 传递参数) // 跨组件
    }
  }
}

接受文件:
// 1. 引入空白vue对象(EventBus)
// 2. 接收方 - $on监听事件
import eventBus from "../EventBus";
export default {
  // 3. 组件创建完毕, 监听send事件(事件名,自定义)
  created() {
    eventBus.$on("send", (参数) => {
         ......
    });
  },
};
生命周期
  1. 从创建到销毁的整个过程就是 – Vue实例的生命周期,拥有四大阶段八个方法:
    在这里插入图片描述
  2. 上述函数执行的总体流程图如下所示:
    created确定能否拿到data,mouted确定能否拿到真实的dom(即文档标签),updated能否获取更新的数据(更新后的真实dom),destory前提: v-if=“false” 销毁Vue实例。主要用于移除全局事件, 移除当前组件, 计时器, 定时器。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
axios使用

axios 是一个专门用于发送ajax请求的库(用于前端异步请求后端的技术),官网: http://www.axios-js.com/, axios 底层还是原生js实现, 内部通过Promise封装的,axios()-原地得到的是Promise对象

网络 ->xhr 进行调试

  1. 发起get请求:
// 1. 下载axios
// 2. 引入axios
// 3. 发起axios请求
import axios from "axios";
// 4. 全局配置
axios.defaults.baseURL = "http://123.57.109.30:3006"//便于后续工作修改
export default {
  data() {
    return {
      bName: "",
      bookObj: { // 参数名提前和后台的参数名对上-发送请求就不用再次对接了
          bookname: "",
          author: "",
          publisher: ""
      }
    };
  },
  methods: {
    findFn() {
      axios({
        url: "/api/getbooks",
        method: "GET",
        params: { // 都会axios最终拼接到url?后面
            bookname: this.bName
        }
      }).then(res => {
          console.log(res);
      })
    },
  1. 发起post请求:
sendFn() {
      axios({
        url: "/api/addbook",
        method: "POST",
        data: {
          appkey: "7250d3eb-18e1-41bc-8bb2-11483665535a",
          ...this.bookObj,
          //等同于下面
          //    bookname: this.bookObj.bookname,
          //    author: this.bookObj.author,
          //    publisher: this.bookObj.publisher
        },//参数名和值, 会被axios拼接到请求体里
      });
    },
$ refs和$nextTick使用
  1. 通过id或ref属性获取原生DOM,下述两个都能打印出标签
    在这里插入图片描述
  2. 通过给组件加入ref属性后,可以再父亲中调用子件内部的方法,下述fn()就是内部的方法(但是不推荐使用这种方法进行通信 ):
    在这里插入图片描述
  3. vue如果数据进行更新之后,不会立刻将其更新到dom中,会把代码都执行完了在更新到dom中,因此如果此时获取dom元素的该属性,则会出现问题,所以就需要语法: **this. n e x t T i c k ( 函数体 ) ∗ ∗ ,等 D O M 更新后 , 触发此方法里函数体执行,或者使用 u p d a t e d 方法, nextTick(函数体)**,等DOM更新后, 触发此方法里函数体执行,或者使用updated方法, nextTick(函数体),等DOM更新后,触发此方法里函数体执行,或者使用updated方法,nextTick函数原地返回也是一个promise对象
 methods: {
        btn(){
            this.count++; // vue监测数据更新, 开启一个DOM更新队列(异步任务)
            // console.log(this.$refs.myP.innerHTML); // 0

            // 原因: Vue更新DOM异步
            // 解决: this.$nextTick()
            // 过程: DOM更新完会挨个触发$nextTick里的函数体
            this.$nextTick(() => {
                console.log(this.$refs.myP.innerHTML); // 1
            })
        }
    }
  1. 在组件内部自定义一个那么属性后,别人就可以使用你自己定义的名字调用自己这个组件:
    在这里插入图片描述
购物车案例
  1. 自定义引入的组件的样式 props,可以使用props的校验方式,如:
组件内部:
<template>
  <div class="my-header" :style="{backgroundColor: background, color}">{{ title }}</div>
</template>

export default {
    props: {
        background: String, // 外部插入此变量的值, 必须是字符串类型, 否则报错
        color: {
            type: String, // 约束color值的类型
            default: "#fff" // color变量默认值(外部不给 我color传值, 使用默认值)
        },
        title: {
            type: String,
            required: true // 必须传入此变量的值
        }
        arr:{
            // 自定义校验规则
          validator(value) {
          // value就是接到数组arr
           if (value.length >= 2 && value.length <= 5) {
            return true; // 符合条件就return true
        } else {
          console.error("数据源必须在2-5项");
          return false;
        }
      },
    }
}
调用者:
 <MyHeader title="购物车案例"></MyHeader>
  1. 把axios添加为一个全局的属性,使其在每个组件中都能够进行使用
main.js:

/ 目标: 请求数据 - 打印
// 1. 下载axios库, main.js - 全局绑定属性 (确保任意.vue文件可以都访问到这个axios方法)
import axios from 'axios'
// 2. 基础地址
axios.defaults.baseURL = "https://www.escook.cn"
// 3. axios方法添加到Vue的原型上
Vue.prototype.$axios = axios
  1. 如果要是进行数据的传递的时候,最好把对象当作一个整体的变量进行传递,不用分开传递。同时这样也方便修改对象的属性,如数量控制要通过对象"互相引用的关系"来影响外面对象里的数量值, 所以最好传对象进来。
  2. 通过label标签的for属性与指定表单元素的id绑定来实现关联表单,见博客
组件切换

实现一个页面动态切换不同的界面,两个的话可以考虑v-if,但是多个不行太麻烦,我们可以采用下述的方法 component是一个内置组件,is是固定的属性,依赖 “is” 的值来决定渲染哪一个组件,但是频繁的切换会导致组件频繁创建和销毁,性能不高,因此可以将其用keep-alive标签包起来,如下:

<template>
  <div>
      <button @click="comName = 'UserName'">账号密码填写</button>
      <button @click="comName = 'UserInfo'">个人信息填写</button>

      <p>下面显示注册组件-动态切换:</p>
      <div style="border: 1px solid red;">
        <keep-alive>
          <component :is="comName"></component>
        </keep-alive>
      </div>
  </div>
</template>

<script>
// 目标: 动态组件 - 切换组件显示
// 场景: 同一个挂载点要切换 不同组件 显示
// 1. 创建要被切换的组件 - 标签+样式
// 2. 引入到要展示的vue文件内, 注册
// 3. 变量-承载要显示的组件名
// 4. 设置挂载点<component :is="变量"></component>
// 5. 点击按钮-切换comName的值为要显示的组件名

import UserName from '../components/01/UserName'//被切换的组件一
import UserInfo from '../components/01/UserInfo'//被切换的组件二
export default {
    data(){
        return {
            comName: "UserName"
        }
    },
    components: {
        UserName,
        UserInfo
    }
}
</script>
  1. 在组建切换的组件内部可以书写两个组件函数,来确定组件是否被激活(即被展示出来),便于后续的其它操作。
export default {
    // 组件缓存下 - 多了2个钩子函数
    activated(){//获得激活状态
        console.log("02-UserName-激活");
    },
    deactivated(){//获得激活状态
        console.log("02-UserName-失去激活");
    }
}
组件插槽
  1. 如果标签不确定,就使用占位,等用的时候给其插 入具体的标签,每次传入的数值都可以不同:
使用的组件,里面的内容会替代slot标签位置,多个插槽可以使用下述方法:
1. slot使用name属性区分名字
2. template配合v-slot:名字来分发对应标签
      <Pannel>
        <template v-slot:title>
          <h4>芙蓉楼送辛渐</h4>
        </template>
        <template v-slot:content>
          <img src="../assets/mm.gif" alt="">
          <span>我是内容</span>
        </template>
      </Pannel>
    
      <Pannel>
          <template #title>//v-slot:可以简化成#
          <span style="color: red;">我是标题</span>
        </template>
        <template #content>
          <p>寒雨连江夜入吴,</p>
          <p>平明送客楚山孤。</p>
          <p>洛阳亲友如相问,</p>
          <p>一片冰心在玉壶。</p>
        </template>
      </Pannel>
      <Pannel></Pannel>

被使用的Pannel组件,如果没有传入数值的时候,会显示默认的内容:
<template>
     <slot name="title">默认显示的内容</slot>
     <slot name="content">默认显示的内容</slot>
</template>

  1. 作用域插槽:使用被使用插槽里面的变量,可以用下面的方法:
    ⚫ 1. 子组件, 在slot上绑定属性和子组件内的值
    ⚫ 2. 使用组件, 传入自定义标签, 用template和v-slot=“自定义变量名” //不能简写,那个是冒号
    ⚫ 3. scope变量名自动绑定slot上所有属性和值
    defaultTwo是defaultObj里面的变量或者属性
    在这里插入图片描述
自定义指令

自己定义指令:

//全局注册,在main.js
// 全局指令 - 到处"直接"使用
// 目标: 自定义指令传值(如果没有值的时候,就只写一个参数,其是获取当前标签)
Vue.directive('color', {
  inserted(el, binding) {//inserted方法 - 指令所在标签, 被插入到网页上触发(一次)
    el.style.color = binding.value
  },
  update(el, binding) {//update方法 - 指令对应数据/标签更新时, 此方法执行
    el.style.color = binding.value
  }
})
//局部注册
<template>
  <div>
      <input type="text" v-focus>
      <p v-color="colorStr">修改文字颜色</p>
  </div>
</template>
export default {
 data(){
        return {
            colorStr: 'red'
        }
    },
    directives: {
        focus: {
            inserted(el){
             el.focus()
            }
        }
    }
}

tabbar案例
  1. 注意我们在v-for里面的循环的变量如果要对每个元素设置属性和方法,不要使用一个名字的变量,最好能找到区别每一个循环项的变量(如id)进行绑定
  2. v-if的使用

VUE路由

基础概念

前端路由:路径和组件的映射关系,主要使用vue-router这个第三方包,单页面应用(SPA): 所有功能在一个html页面上实现
前端路由作用: 实现业务场景切换。
⚫ 优点:整体不刷新页面,用户体验更好。 数据传递容易, 开发效率高
⚫ 缺点: 开发成本高(需要学习专门知识)。 首次加载会比较慢一点。不利于seo

  1. 组件分类:vue文件分2类, 一个是页面组件, 一个是复用组件(本质并无区别)
    src/views文件夹: 页面组件 - 页面展示 - 配合路由用
    src/components文件夹:复用组件 - 展示数据/常用于复用
  2. vue-router的使用(一般固定写法):
main.js:
import Vue from 'vue'
import App from './App.vue'
import Find from '@/views/Find' // @是src的绝对地址
import My from '@/views/My'
import Part from '@/views/Part'
import NotFound from '@/views/NotFound'
// 目标: vue-router基础使用
// 1. 下载vue-router  (yarn add vue-router)
// 2. 引入
import VueRouter from 'vue-router'
// 3. 注册全局组件
Vue.use(VueRouter)
// 4. 规则数组
const routes = [
  //路径从上到下逐一配对
  //重定向,默认打开的路径
  {
    path: "/", // 默认hash值路径
    redirect: "/find" // 重定向到/find
    // 浏览器url中#后的路径被改变成/find-重新匹配规则
  },
  {
    path: "/find",
    name: "Find",
    component: Find,
   },
  {
    path: "/my",
    name: "My",
    component: My
  },
  {
    path: "/part",
    name: "Part",
    component: Part
  },
  {
    path: "/part/:username", // 有:的路径代表要接收具体的值
    component: Part
  },
  // 404在最后(规则是从前往后逐个比较path)
  {
    path: "*",
    component: NotFound
  }
]
// 5. 生成路由对象
const router = new VueRouter({
  routes,// routes是固定key(传入规则数组)
  // mode: "history" // 默认不写是"hash"
})

Vue.config.productionTip = false

// 6. 路由对象注入到vue实例中, this可以访问$route和$router
new Vue({
  router,
  render: h => h(App),
}).$mount('#app')


在使用的App.vue文件中:
<template>
  <div>
    <div class="footer_wrap">
      <a href="#/find">发现音乐</a>
      <a href="#/my">我的音乐</a>
      <a href="#/part">朋友</a>
    </div>
    <div class="top">
      <!-- 7. 设置挂载点-当url的hash值路径切换, 显示规则里对应的组件到这 -->
      <router-view></router-view>
    </div>
  </div>
</template>
声明式导航
  1. vue-router提供了一个全局组件 router-link,router-link实质上最终会渲染成a链接 to属性等价于提供 href属性(to无需#)。router-link提供了声明式导航高亮的功能(自带类名)
App.vue文件中:
<template>
  <div>
    <div class="footer_wrap">
      <router-link to="/find">发现音乐</router-link>
      <router-link to="/my">我的音乐</router-link>
      <router-link to="/part">朋友</router-link>
    </div>
    <div class="top">
      <router-view></router-view>
    </div>
  </div>
</template>

<script>
// 目标: 声明式导航 - 基础使用
// 本质: vue-router提供的全局组件 "router-link"替代a标签
// 1. router-link 替代a标签
// 2. to属性      替代href属性
// 好处: router-link自带高亮的类名(激活时类名)
// 3. 对激活的类名做出样式的编写
export default {};
</script>
<style scoped>
.footer_wrap {
  position: fixed;
  left: 0;
  top: 0;
  display: flex;
  width: 100%;
  text-align: center;
  background-color: #333;
  color: #ccc;
}
.footer_wrap a {
  flex: 1;
  text-decoration: none;
  padding: 20px 0;
  line-height: 20px;
  background-color: #333;
  color: #ccc;
  border: 1px solid black;
}
.footer_wrap a:hover {
  background-color: #555;
}
.top {
  padding-top: 62px;
}

/*激活时样式 */
.footer_wrap .router-link-active{
  color: white;
  background: black;
}
</style>
路由传值的方式

第一种:$route.query.参数名   接收参数
<router-link to="/part?name=小传">朋友-小传{{$route.query.name}}</router-link>
第二种: $route.params.参数名   接收参数
<router-link to="/part/小智">朋友-小智{{$route.params.username}}</router-link>
 main.js
 {
    path: "/part/:username", // 有:的路径代表要接收具体的值
    component: Part
  },
编程式导航
  1. 路由的模式:
    ⚫ hash路由例如: http://localhost:8080/#/home
    ⚫ history路由例如: http://localhost:8080/home (以后上线需要服务器端支持, 否则找的是文件夹)
const router = new VueRouter({
  routes,// routes是固定key(传入规则数组)
  // mode: "history" // 默认不写是"hash"
})

  1. 使用js代码实现路由的跳转:
APP.VUE:
<template>
  <div>
    <div class="footer_wrap">
      <span @click="btn('/find', 'Find')">发现音乐</span>
      <span @click="btn('/my', 'My')">我的音乐</span>
      <span @click="btn('/part', 'Part')">朋友</span>
    </div>
    <div class="top">
      <router-view></router-view>
    </div>
  </div>
</template>

<script>
// 目标: 编程式导航 - js方式跳转路由
// 语法:
// this.$router.push({path: "路由路径"})
// this.$router.push({name: "路由名"})
// 注意:
// 虽然用name跳转, 但是url的hash值还是切换path路径值
// 场景:
// 方便修改: name路由名(在页面上看不见随便定义)
// path可以在url的hash值看到(尽量符合组内规范)
export default {
//方式一:
  // methods:{
  //    btn(targetPath){
  //     // 方式1: path跳转
  //     this.$router.push({
  //       path: targetPath,
  //     })
  //   }
  // }
//方式二:需在main.js路由那里给路径定义name值
  methods: {
    btn(targetPath, targetName){
      this.$router.push({
        name: targetName
      })
    }
  }
};
</script>
  1. js跳转路径并且进行传参(给对应路径下的文件进行传参)。 path会自动忽略params,主要是看上述方法选择方法几:query传, $route.query接;params传, $route.params接,使用其中一个就行
    在这里插入图片描述
嵌套和守卫
  1. 路由的嵌套
 main.js– 继续配置2级路由
⚫ 一级路由path从/开始定义
⚫ 二级路由往后path直接写名字, 无需/开头
⚫ 嵌套路由在上级路由的children数组里编写路由信息对象
记得引入页面组件
 {
    path: "/find",
    name: "Find",
    component: Find,
    children: [
      {
        path: "recommend",
        component: Recommend
      },
      {
        path: "ranking",
        component: Ranking
      },
      {
        path: "songlist",
        component: SongList
      }
    ]
  },
然后再对应的find组件中定义路由
 <div class="nav_main">
      <router-link to="/find/recommend">推荐</router-link>
      <router-link to="/find/ranking">排行榜</router-link>
      <router-link to="/find/songlist">歌单</router-link>
    </div>

    <div style="1px solid red;">
      <router-view></router-view>
    </div>
  1. 虽然二级路由激活的时候还是那个类名,但是vue在处理的时候会进行区分,具体如下:
    ⚫ router-link-exact-active (精确匹配) url中hash值路径, 与href属性值完全相同, 设置此类名(第二级)
    ⚫ router-link-active (模糊匹配) url中hash值, 包含href属性值这个路径(第一级)
  2. 路由守卫:路由跳转之前, 会触发一个函数,进行权限的判断
//目标:路由守卫 
//场景:当你要对路由权限判断时 
语法:router .beforeEach ((to,from,next)=>{//路由跳转"之前"先执行这里,决定是否跳 转}) 
参数1:要跳转到的路由(目标路由对象信息) 
参数2:从哪里跳转的路由(来源 路由对象信息) 
参数3:函数体-next()才会让路由正常的跳转切换,
      next(false )在原地停留,next("强制修 改到另一个路由路径上") 
//注意:如果不调用next,页面留在原地工

如下图的例子所示://main.js文件中
在这里插入图片描述

Vant组件库

Vant是一个轻量、可靠的移动端 Vue 组件库, 开箱即用(引用下载的时候注意看清是vue的版本)
网址:https://vant-contrib.gitee.io/vant/#/zh-CN/

解决跨域,可以在本地写一个服务器(node.js)可以去百度上去找对应的API的代码,再用服务器去访问跨域的资源,因为跨域是针对浏览器之间的,服务器是可以进行访问的

VUE3

详见笔记:http://zhoushugang.gitee.io/erabbit-client-pc-document/

VUE 原理

尝试使用原生的js实现VUE的功能,便于对基本原理的掌握,详见笔记https://cp_fe.gitee.io/course-advance/#/

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值