[网站]Vue2+Vue3学习笔记
本文最后更新于 332 天前,其中的信息可能已经有所发展或是发生改变。
不要问我为啥又学Vue2,要参加的比赛居然还用Vue2!!!

参考

JavaScript高级起步

  • 【黑马程序员前端JavaScript入门到精通全套视频教程,javascript核心进阶ES6语法、API、js高级等基础知识和实战教程】https://www.bilibili.com/video/BV1Y84y1L7Nn?p=157

1.APIs -133数组

1.1 数组map和join的方法

map可以遍历数组处理数据,并且返回新的数组。
map重点在于有返回值,forEach没有返回值

    const arr = [20,30,40]
    const newArr =arr.map(function(ele,index){
        console.log(ele,index); // 数组元素 数组索引号
        return ele+'岁'
    })
    console.log(newArr); // ['20岁', '30岁', '40岁']

join() 方法用于把数组中所有元素转换成一个字符串
数组元素是通过参数里面指定的分隔符进行分隔的,空字符串(”),则所有元素之间都没有任何字符。

    const arr = [20,30,40]
    console.log(arr.join('')); //203040

2.2函数参数

2.2.1动态参数

1、arguments是函数内部内置的伪数组变量,包含了调用函数时所传入的所有实参
2、注意:它是个伪数组,它只存在于函数中

function getSum(){
    let sum = 0
    for(let i = 0; i<arguments.length; i++){
        sum += arguments[i]
    }
    return sum
}

2.2.2剩余参数

1、...是语法符号,置于最末形参之前,用于获取多余的实参(没错,这个...就是剩余参数)
2、借助...获取剩余的实参,是个真数组
3、开发中用于获取多余的实参
funtion sum(...arr){}

开发中,提倡多使用剩余参数

这里补充一个 展开运算符

展开运算符是可以运用在数组
它的作用是用来展开数组的,并不会修改原数组
典型运用场景:求数组最大值,最小值

2.3箭头函数(重要)

// 之前写法
    const sum = function(x){
        return x+x
    }
    console.log(sum(1))
// 箭头函数
    const sum = (x) => x+x
    console.log(sum(1))

    const sum = x => x+x
    console.log(sum(1))
// 箭头函数可以直接返回一个对象。当然,正如下面所说,只有一个实参时,这里(uname)中的()也是可以省略的
    //                     属性名:属性值
    const fn = (uname) => ({name:uname})
    console.log(fn('张三'));

可以看到,省略了花括号{},并且也无需return,甚至当只有一个实参时,(x)中的()也是可以省略的,只留下x
注意这里仍然没有使用花括号{},因此无需return

    const fn = (uname,gender) => (
        {   name:uname,
            gender:gender,
        }
    )
    console.log(fn('张三','男'));
// 控制台输出 {name: '张三', gender: '男'}

1、箭头函数属于表达式函数,因此不存在函数提升
2、箭头函数只有一个参数时可以省略圆括号
3、箭头函数函数日只有一行代码时可以省略花括号,并自动为返回值被返回
4、加括号的函数体返回对象字面量表达式

学到这里你可能想用剩余参数加上箭头函数,这是可以的。但注意,箭头函数并没有arguments,所以只能使用剩余参数

接着是thisthis是谁调用的this就指向谁;但是在这里,箭头函数没有自己的this,它只会从自己的作用域链的上一层沿用this

    const obj = {
        uname:'pink老师',
        sayHi: function(){
            console.log(this);
        }
    }
    obj.sayHi()
// 这两个的this指向是不一样的上面指向obj 下面指向window
    const obj = {
        uname:'pink老师',
        sayHi: () => {
            console.log(this);
        }
    }
    obj.sayHi()

只有函数里面才会有this

    // 普通函数,此时this指向DOM对象
    btn.addEventListener('click', function(){
        console.log(this);
    })
    // 箭头函数,此时this对象指向window
    btn.addEventListener('click',() =>{
        console.log(this);
    })

在DOM事件回调函数为了方便,还是不太推荐使用箭头函数。更多this问题,我们后面再详细说说。P157

3解构赋值

3.3 数组对象解构

单一数组对象解构

    const obj = [
        {
            name: '张三',
            age: 18
        }
    ];
    // 数组对象解构
    [{name,age}] = obj
    console.log(name);
    // 对解构的变量名进行重命名
    // 旧名:新名
    [{name:username,age: ages}] = obj
    console.log(username);

多级对象解构

    const pig= {
        name: '小猪佩奇',
        family : {
            father: '猪爸爸',
            mother: '猪妈妈'
        },
        age: 5
    }
    // 对象解构
    const {name, family, family: {father, mother}, age} = pig
    console.log(name);
    console.log(family);
    console.log(father);
    console.log(mother);
    console.log(age);

多级对象数组解构

    const msg={
        "code": 200,
        "msg": "success",
        "data":[
            {
                "id": 1,
                "title": "5G商用,三大运营商收入下降",
                "count": 100
            },
            {
                "id": 2,
                "title": "突发,美国宣布对华为实施新制裁",
                "count": 510
            },
            {
                "id": 3,
                "title": "俄乌战争持续冲突",
                "count": 1669
            }
        ]
    }
    // 取出data
    // 1.const { data } = msg;
    // 或
    // function render(msg) {
    //     const {data} = msg
    //     console.log(data);
    // }

    // 上面这种写法显然麻烦,让我们换一种写法
    function render({data}){
        // 相当于 const {data} = msg,这里只接受data
        console.log(data);
    }
    // 当然,也可以重命名
    function render({data:myData}){
        console.log(myData);
    }

    render(msg)

4.遍历数组 forEach 方法(重点)

forEach() 方法用于调用数组的而每一个元素,并将元素传递给回调函数
主要使用场景:遍历数组的每个元素,不返回值

//语法(加强版的 for 循环):
被遍历的数组.forEach(function (当前数组元素,当前元素索引号){函数体}
//例如:
// forEach 就是遍历  加强版的for循环  适合于遍历数组对象
    const arr = ['red', 'green', 'pink']
    const result = arr.forEach(function (item, index) {
      console.log(item)  // 数组元素 red  green pink
      console.log(index) // 索引号 0 1 2
    })
// console.log(result) // undefined

注意:forEach主要是遍历数组
参数当前数组元素必须要写,索引号可选

5.筛选数组 filter 方法(重点)

filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素
主要使用场景:筛选数组符合条件的元素,并返回筛选之后元素的新数组

// 语法
    被遍历的数组.filter(function(currentValue,index){
        // 返回值为true,保留,false,删除
        return 筛选条件
    })  
// 例如
     // 遍历数组,返回一个指定条件新数组
    const arr = [20,30,40]
    const newArr = arr.filter(item => {
        // console.log(item);
        return item > 20
    })
    console.log(newArr); // (2) [30, 40]

静态方法(内置构造函数)

Object

    const o = {name:'pink',age:18}
    const oo = {}
    console.log(Object.keys(o));  // ['name','age']
    console.log(Object.values(o)); // ['pink',18]
    console.log(Object.assign(oo,o)); // oo ={name:'pink',age:18}
    console.log((Object.assign(o,{gender:'女'}))) // {name: 'pink', age: 18, gender: '女'}

Array

方法作用说明
forEach遍历数组不返回数组,经常用于查找遍历数组元素
filter过滤数组返回新数组,返回的是筛选满足条件的数组元素
map迭代数组返回新数组,返回的是处理之后的数组元素,想要使用返回的新数组
reduce累计器返回累计处理的结果,经常用于求和等
    arr = [1,2,3,4,5]
    // arr.reduce(function(上一次值,当前值,当前索引,当前数组){
    //     return 上一次值 + 当前值
    // },初始值)
    // 初始值可选,不传默认为0,上一次值默认为初始值。
    // arr.reduce(function(上一次值,当前值){},初始值)
    // 简单写法 arr.reduce(function(pre,cur){return pre + cur},0)
    const sum = arr.reduce(function(pre,cur,index,arr){
        console.log(pre,cur,index,arr);
        return pre + cur
    },0)
    console.log(sum); // 15
//箭头函数
    const totals = arr.reduce((prev,cur) => prev+cur,0)
    console.log(totals); // 15

接下来是其他方法(部分已经讲过)
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array

  • 实例方法 join 数组元素拼接字符串,返回字符串(重点)
  • 实例方法 find 查找元素,返回符合测试条件的第一个数组元素值,如果没有符合条件的则返回 undefined(重点)
  • 实例方法 every 检测数组所有元素是否都符合指定条件,如果所有元素都通过检测返回 true,否则返回 false(重点)

String

实例方法 split 把字符串转数组

    const strs = 'pink,red'
    const arrs = strs.split(',')
    console.log(arrs); // ['pink', 'red']

本地存储数据

持久化:

// 存储
    watch:{
      list:{
        deep:true,
        handler(newVlaue){
          localStorage.setItem('list',JSON.stringify(newVlaue))
        }
      }
    }
// 取出
    list:JSON.parse(localStorage.getItem('list')) || {}

起步

NodeJS

安装完成后,可使用在命令行输入 node -v 查看nodejs版本号
安装完nodejs后,防止因网络原因 拉取/下载 项目失败,请务必使用国内镜像源。
命令如下(镜像源由npmmirror 镜像站提供)

npm config set registry https://registry.npmmirror.com

Vue-Cli

在命令提示符中输入

npm install -g @vue/cli

vue-cli版本号:在命令行输入 vue -V 即可查看
vue版本号:需要在Vue项目目录内,使用 npm list vue 即可查看

Vue2

创建基于Vue-Cli项目的架子

在命令行内输入

vue create project-name
// 稍等片刻你将看到
Vue CLI v5.0.8
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Vuex, Linter
? Choose a version of Vue.js that you want to start the project with 2.x
? Use history mode for router? (Requires proper server setup for index fallback in production) No
? Pick a linter / formatter config: Basic
? Pick additional lint features: Lint on save
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No

Vue CLI v5.0.8
✨  Creating project in D:\Filedata\web\project\anjnds_project\ah.
🗃  Initializing git repository...
⚙️  Installing CLI plugins. This might take a while...


added 872 packages in 19s

100 packages are looking for funding
  run `npm fund` for details
🚀  Invoking generators...
📦  Installing additional dependencies...


added 90 packages in 3s

112 packages are looking for funding
  run `npm fund` for details
⚓  Running completion hooks...

📄  Generating README.md...

🎉  Successfully created project ah.
👉  Get started with the following commands:

 $ cd ah
 $ npm run serve

参考视频:088-基于VueCli自定义创建项目_哔哩哔哩_bilibili

使用 cd 命令进入你的项目目录
使用 npm run server 启动Vue项目,打开浏览器访问 http://localhost:8080/ 欢迎页面
至此你已完成Vue项目的创建

050组件通信

父子关系

props和$emit

  1. 父组件通过props将数据传递给子组件
  2. 子组件利用$emit通知父组件修改更新

父→子

// App.vue
    <div>
      <son-view :title="SonTitle"/>
    </div>
<script>
import SonView from '@/views/SonView.vue'
export default {
  components: {
    SonView,
  },
  data () {
    return {
      SonTitle: 'Welcome to Your itheima'
    }
  },
}
</script>
// SonView.vue
<template>
    <div>
        <h1>SonView</h1>
        <h2>{{ title }}</h2>
    </div>
</template>

<script>
export default {
    props: {
        title: {
            type: String,
            // required: true
        }
    }
}
</script>

子→父

// App.vue
<son-view :title="SonTitle" @changeTitle="changeFn"/>
  methods: {
    // 
    changeFn(newTitle){
      this.SonTitle = newTitle
    }
  }

// SonView.vue
<template>
    <div>
        <h1>SonView</h1>
        <h2>{{ title }}</h2>
        <button @click="handleClick">向父组件通知</button>
    </div>
</template>

<script>
export default {
    props: {
        title: {
            type: String,
            // required: true
        }
    },
    methods: {
        handleClick () {
            //          告诉父组件,修改成啥
            this.$emit('changeTitle','子组件通知父组件')
        }
    }
}
</script>

父子通信方案的核心流程
父传子:props:
1、父中给子添加属性传值 2、子props接收 3、使用
子传父$emit:
1、子$emit发送消息 2、父中给子添加消息监听 3、父中实现处理函数
// 数组可使用join(”)完成转换

props校验

    // 完整写法(类型、非空、默认、自定义)
    props:
        校验的属性名: {
            type: 类型,// Number String Boolean
            required: true,// 是否必填
            default: 默认值,// 默认值
            validator (value){
                // 自定义校验逻辑
                return 是否通过校验
                }
            }
        },

完整代码如下

// Vue.app
<template>
  <div id="app">
    <div>
      <!--                          事件名 父组件处理函数 -->
      <son-view :title="SonTitle" @changeTitle="changeFn" 
      :username="name"
      :userage="age"
      :issingle="isSingle"
      :car="car"
      :hobby="hobby"
      />
    </div>
    <router-view/>
  </div>
</template>

<script>
import SonView from '@/views/SonView.vue'

export default {
  components: {
    SonView,
  },
  data () {
    return {
      SonTitle: 'Welcome to Your itheima',
      name: 'itheima',
      age: 18,
      isSingle: true,
      car: {brand: 'BMW',},
      hobby: ['coding', 'reading', 'running']
    }
  },
  methods: {
    // 
    changeFn(newTitle){
      this.SonTitle = newTitle
    }
  }
}
</script>
// SonView.vue
<template>
    <div>
        <h1>SonView</h1>
        <h2>{{ title }}</h2>
        <button @click="handleClick">向父组件通知</button>
        <ul>
            <li><h2>个人信息</h2></li>
            <li>姓名:{{ username }}</li>
            <li>年龄:{{ userage }}</li>
            <li>是否单身:{{ issingle ? '是' : '否'}}</li>
            <li>座驾:{{ car.brand }}</li>
            <li>兴趣爱好:{{ hobby.join('、') }}</li>
        </ul>
    </div>
</template>

<script>
export default {
    props: 
    // ['title', 'username','userage','issingle','car','hobby'],
    {
        title: {
            type: String,
            required: true
        },
        username: String,
        userage: {
            type: Number,
            required: true,
            default: 18,
            validator(value){
                console.log(value);
                if(value<0 || value >150){
                    console.error("年龄校验错误 您输入的是 userage 年龄不得小于0且不得大于150");
                    return false
                }else{
                    return true
                }
            }

        },
        issingle: Boolean,
        car: Object,
        hobby: Array
    },
    methods: {
        handleClick () {
            //          告诉父组件,修改成啥
            this.$emit('changeTitle','子组件通知父组件')
        }
    }
}
</script>

非父子关系

  1. provide & inject
  2. eventbus

todo

通用解决方案 Vuex(适合复杂业务场景)

v-model详解

v-model实际上就是 :value=”msg” 和 @input=”msg = $event.target.value”

表单类组件封装

// FatherView.vue
<SonView :select="selectId" @selectCityId="selectId=$event"></SonView>
<script>
import SonView from '@/views/SonView.vue'
export default {
    components: {
        SonView
      },
    data() {
      return{
        selectId:'102',
      }
    },
}
</script>
// SonView.vue
拆解 :value="父组件传来的值"  @change="handleSelect"
<script>
export default {
    props:{
        select:{
            default:'101'
        }
    },
    methods:{
      handleChangeSelect(e){
        this.$emit("selectCityId",e.target.value)
      }
    }

}
</script>
// 再来
<SonView v-model="selectId"></SonView>

<select :value="value" @change="handleChangeSelect"></select>
props:{value:String},
methods:{
   handleChangeSelect(e){this.$emit("input",e.target.value)}
}

.sync修饰符

:属性名 和 @update:属性名 合写

<BaseDialog :value="isShow" @update="isShow = $event"/>
<BaseDialog :visible.sync="isShow"/>
// 以上二选一
props:{visible:Boolean},
this.$emit('update.属性名',false)

$nextTick()

this.$nextTick(()=>{ /* 业务逻辑*/ })

自定义指令

// 全局注册
Vue.directive('指令名', {
  'inserted' (el) {
    // 可以对el标签,扩展额外功能
    el.focus()
  }
})
// 局部注册
directives:{
  '指令名':{
    inserted(el){
      el.focus()
    }
  }
}
// 使用
<input v-指令名="" type="text">
// 补充 binding.value可以拿到指令值如:v-color="pink"
inserted(el,binding){}
update(el,binding){}

el.classList.add(“css样式标签”)

插槽

加油!继续学!
// 不同页面数据调用(仅为示例)
// SonView.vue
<main v-for="(item,index) in list" :key="item.id">
    <slot name="body" :item="item" :index="index"></slot>
</main>
// FatherView.vue
<main>
    <template #body="obj"> //或者解构 {item,index}
        <tr>
            <td>{{ obj.index+1 }}</td>
            <td>{{ obj.name }}</td>
            <td>{{ obj.sex }}</td>
        </tr>
    </template>
</main>

单页应用程序

单页面应用(SPA):Single Page Application

路由(Vue Router)

安装:安装 | Vue Router↗
按照(2 3 3 \3 4 4):即 Vue2 VueRouter3.x Vuex3.x \ Vue3 VueRouter4.x Vuex4.x
关于Vuex后面会介绍到。

安装命令:

npm install vue-router@3.6.5

自定义高亮类名

<router-link to="/my"/> ,会自带类名,可以通过下面的方式自定义类名。
routes:[] 同级别下使用 linkActiveClass:'自定义类名',linkExactActiveClass:'自定义类名'

路由传参

查询参数传参(适合传多个参数)
$route.query.参数名 如:/search?keys=黑马程序员 $route.query.keys
动态路由传参(优雅,适合传单个参数)
$route.params.参数名 如:/search/黑马程序员 $route.params.keys 另:路由需配置为/search/:keys
注:/search/:keys 表示必须传参,如果不传参数,也希望匹配,可以加个可选符”?

编程式导航

通过路径跳转(简单方便)
this.$router.push("路由路径")
this.$router.push({path:"路由路径"})

通过路由名字跳转(适合路径名字长的场景)
this.$router.push({name:"路由名"})
{name:"路由名",path:"/path/XXX",...}

Vue3

根据《黑马程序员》的教程来安装PNPM来继续进行

参考

pnpm 基本详细使用教程(安装、卸载、使用、可能遇到的问题及解决办法)-CSDN博客

起步

Vue.js – 渐进式 JavaScript 框架 | Vue.js (vuejs.org)

安装PNPM

npm i -g pnpm

创建项目Vue3

在命令行内输入

pnpm create vue
// 随后你将看到
C:\Users\Desktop\web>pnpm create vue
.../1900adaf91d-4da0                     |   +1 +
.../1900adaf91d-4da0                     | Progress: resolved 1, reused 1, downloaded 0, added 1, done

Vue.js - The Progressive JavaScript Framework

√ 请输入项目名称: ... project-name
√ 是否使用 TypeScript 语法? ... 否 / 是
√ 是否启用 JSX 支持? ... 否 / 是
√ 是否引入 Vue Router 进行单页面应用开发? ... 否 / 是
√ 是否引入 Pinia 用于状态管理? ... 否 / 是
√ 是否引入 Vitest 用于单元测试? ... 否 / 是
√ 是否要引入一款端到端(End to End)测试工具? » 不需要
√ 是否引入 ESLint 用于代码质量检测? ... 否 / 是
√ 是否引入 Vue DevTools 7 扩展用于调试? (试验阶段) ... 否 / 是

正在初始化项目 C:\Users\Desktop\web\project-name...

项目初始化完成,可执行以下命令:

  cd project-name
  pnpm install
  pnpm dev

请根据实际开发来选择,一般来说会选择Vue Router和Pinia。

来自安徽
本博客所有文章除特别声明外,均采用署名-非商业性使用-相同方式共享 4.0进行许可,仅供个人学习使用。
上一篇
下一篇