Vue2笔记

Vue2

前端 · 语雀 (yuque.com)

vue3: https://github.com/Panyue-genkiyo/vue3-learning

vue2依据脚手架:https://github.com/Panyue-genkiyo/vue-advance

vue基础不依赖脚手架:https://github.com/Panyue-genkiyo/vue-learning

Vue 是一套用于构建用户界面的 渐进式框框架 可自底向上逐层应用

渐进式就是逐步实现新特性的意思。如实现模块化开发 路由 状态管理的新特性 其特点是综合了Angular(模块化)和React(虚拟DOM)的优点

image-20220610164317765

网络通讯:axios 前端通讯框架

页面跳转:vue-router

状态管理:vuex

Vue-UI:ICE

vue 特点

  • 采用 组件化 模式,提高代码复用率,并且更好维护
  • 声明式 编码 无需操作 DOM 提供开放效率

模板语法

<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>

<div id="app">
    <h1>{{ message }}</h1>
</div>

<script>
    var app = new Vue({
        el: '#app',
        data: {
            message: 'Hello Vue! '
        }
    })
</script>

数据绑定

v-bind 单向绑定

<a v-bind:href="url">点击</a>
<a :href="url">点击</a>

v-model 双向绑定

Vue中有2种数据绑定的方式:

​ 1.单向绑定(v-bind):数据只能从data流向页面。

​ 2.双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向data。

备注:

​ 1.双向绑定一般都应用在表单类元素上(如:input、select等)

​ 2.v-model:value 可以简写为 v-model,因为v-model默认收集的就是value值。

v-model:value 简写 v-model 因为 v-model 默认收集的就是 value 值

<input type="text" v-model="message">
<h1>{{ message }}</h1>

el 的两种写法

var app = new Vue({
    el: '#app',
    data: {
        message: 'Hello Vue! ' + new Date().toLocaleString(),
        url: 'http://www.baidu.com'
    }
})
var app = new Vue({
    data: {
        message: 'Hello Vue! ' + new Date().toLocaleString(),
        url: 'http://www.baidu.com'
    }
})
// 挂载
app.$mount('#app')

data 的两种写法

对象式

var app = new Vue({
    el: '#app',
    data: {
        message: 'Hello Vue! ' 
    }
})

函数式

var app = new Vue({
    el: '#app',
    data()  {
        message: 'Hello Vue! ' 
    }
})

生命周期

  • 在 Vue 实例初始化时,Vue 将调用 $mount() 方法
  • 在 Vue 实例挂载到 DOM 时,Vue 将调用 $mount() 方法
  • 在 Vue 实例被销毁时,Vue 将调用 $destroy() 方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YFLmh6C2-1689212938289)(http://qiniu.xiaotao.cloud/生命周期.png)]

常用生命周期钩子
  • mounted():发送 ajax 请求 启动定时器 初始化数据 创建子组件 绑定自定义事件 订阅信息等
  • beforeDestroy():销毁子组件 取消订阅信息 移除自定义事件 移除定时器

​ 销毁后借助vue开发着工具看不到任何信息·

​ 销毁后自定义事件失效 但原生DOM事件仍然可以触发

js 调式

debugger;

MVVM (Model-View-ViewModel)

是一种软件架构设计模式 是一种简化用户界面的事件驱动编程方式

MVVM 源自于经典的MVC 模式

MVVM 的核心是 ViewModel 层 负责转化Model 中的数据对象来让数据更加容易管理和使用

M : 模型(Model) 对应 data 中的数据

V : 试图(View) 模块

VM : 试图模型(ViewModel) Vue 实例对象

image-20220610181906620

数据代理

回顾:

Object.defineProperty

let number = 18;
let person = {
    name: '张三',
    sex: '男'
}
Object.defineProperty(person, 'age',{
    // value: 18,
    enumerable:true,  // 控制属性是否可以枚举, 默认为 false
    writable: true,   // 控制属性是否可以修改, 默认为 false
    configurable: true,  // 控制属性是否可以删除, 默认为 false

    // 当有人读取 person 的 gae 时 get 就会被调用,并且返回值就是 age 的值
    get (){
        return number
    },

    // 当有人写入 person 的 age 时 set 就会被调用,并且传入的值就是 age 的值
    set (value){
        console.log(value);
    }

})

数据代理:通过一个对象代理另一个对象中的属性的操作(读 写)

let obj1 = {x:100}
let obbj2 = {y:200}

Object.defineProperty(obj2, 'x',{
    get (){
        return obj1.x
    },
    
    set (value){
    	obj.x = value	
    }
})

vue 数据代理

image-20220610232055546

vue2 vue3 响应式原理

vue2: Object.defineProperty

vue3: Proxy(代理)Reflect(反射)

let person = {
            name: 'xiaotao',
            age: 18
        }

        // 模拟vue2中实现响应式
        let p = {}
        Object.defineProperty(p, 'name', {
            get() {  // 有人读取name时调用
                return person.name
            },
            set(newValue) {  // 有人修改name时调用
                console.log('有人修改name属性 我要去更新页面');
                person.name = newValue
            }
        })
        Object.defineProperty(p, 'age', {
            get() {  // 有人读取age时调用
                return person.age
            },
            set(newValue) {  // 有人修改age时调用
                console.log('有人修改age属性 我要去更新页面');
                person.age = newValue
            }
        })


        // 模拟vue3中实现响应式
        /* - 通过Proxy(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。
           - 通过Reflect(反射): 对源对象的属性进行操作。 */
        let proxy = new Proxy(person, {
            get(target, key) {
                console.log(`有人读取 ${key} 属性`);
                return Reflect.get(target, key)
            },
            set(target, key, value) {
                console.log(`有人修改或添加 ${key} 属性 我要去更新页面`);
                return Reflect.set(target, key, value)
            },
            deleteProperty(target, key) {
                console.log(`有人删除 ${key} 属性 我要去更新页面`);
                return Reflect.deleteProperty(target, key)
            }
        })

mixin 混入

作用: 将一段需要重复 编写的方法 抽离出来 定义下成为一个全局可以使用的组件

方便代码复用

mixin.js

export const mixin = {
    methods: {
        showName() {
            alert(this.name);
        }
    }
}

全局混入

main.js

// 全局引入混合
import {mixin} from './mixin'

Vue.mixin(mixin)

new Vue({
  render: h => h(App),
}).$mount('#app')

局部混入

<template>
    <div>
        <h3 @click="showName">学生姓名:{{name}}</h3>
    </div>
</template>

<script>
    import { mixin } from '../mixin' 
   export default {
       name: 'Student',
       data() {
           return {
                name: '张三'
           }
       },
        mixins: [mixin]
   }
</script>

vue 插件 plugins

增强 vue 的使用

plugins.js

export default {
    install(Vue, x, y, z) {
        console.log(x, y, z);
        console.log('install', Vue);    
        // 全局过滤器
        Vue.filter('mySlice', function(value) {return value.slice(0, 4)});

        // 全局指令
        Vue.directive('fbind', {
            // 指令与元素成功绑定时
            bind(el, binding, vnode) {
                console.log('bind');
                el.value = binding.value;
            },
            // 指令所在元素被插入页面时
            inserted(el, binding, vnode) {
                console.log('inserted');
                el.focus();
            },
            // 指令所在模板被重新解析时
            update(el, binding, vnode) {
                console.log('update');
                el.value = binding.value;
            }
        });

        // 全局混合
        Vue.mixin({
            data() {return {a: 1, b: 2}},
        });

        // 给 Vue 原型添加一个方法
        Vue.prototype.hello = function() {
            console.log('hello');
        }
    }
}

main.js

// 引入自定义插件
import plugins from './plugins'
// 使用插件
Vue.use(plugins)

浏览器本地存储

localStorage

localStorage.setItem('data', JSON.stringify(data));

let data = localStorage.getItem('data');

localStorage.removeItem('msg');

localStorage.clear();

sessionStorage

sessionStorage.setItem('data', JSON.stringify(data));

let data = sessionStorage.getItem('data');

sessionStorage.removeItem('msg');

sessionStorage.clear();

Axios

是一个开源的可在浏览器端 和 NodeJS 的异步通信框架 主要作用就是实现AJAX 的异步通信

功能:

  • 从浏览器创建 XMLHttpRequests
  • 从node.js 创建 http 请求
  • 支持 Promise API [js 链式编程]
  • 拦截请求和响应
  • 转换请求数据和响应数据
  • 取消请求
  • 自动转化 JSON 数据
  • 客户端支持防御 XSPF (跨站请求伪造)

为什么使用?

由于 Vue.js 是一个视图层框架 并且严格遵守 SoC(关注度分离原则) 所以 Vue 不包含 AJAX 的通信功能 为了解决通信问题

作者单独开发 vue-resource , 2.0 后停止更新 推荐使用 Axios 框架

{
  "name": "狂神说Java",
  "url": "https://blog.kuangstudy.com",
  "page": 1,
  "isNonProfit": true,
  "address": {
    "street": "含光门",
    "city": "陕西西安",
    "country": "中国"
  },
  "links": [
    {
      "name": "bilibili",
      "url": "https://space.bilibili.com/95256449"
    },
    {
      "name": "狂神说Java",
      "url": "https://blog.kuangstudy.com"
    },
    {
      "name": "百度",
      "url": "https://www.baidu.com/"
    }
  ]
}

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<div id="app">
			<div>{{info.name}}</div>
			<div>{{info.address.country}}</div>
			<a v-bind:href="info.url">点我</a>
		</div>
		
		<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
		<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
		<script type="text/javascript">
			var vm = new Vue({
				el:"#app",
				data() {
					return{
						info: {
							name: null,
							address: {
								country: null,
								city: null,
								street: null
							},
							url: null
						}
					}
				},
				mounted() {  //钩子函数  链式编程
					axios
						.get('data.json')
						.then(response => (this.info = response.data));
				}
			})
		</script>
	</body>
</html>

计算属性

1.定义:要用的属性不存在,要通过已有属性计算得来。

2.原理:底层借助了Objcet.defineproperty方法提供的getter和setter。

3.get函数什么时候执行?

(1).初次读取时会执行一次。

​ (2).当依赖的数据发生改变时会被再次调用。

4.优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便

5.备注:

​ 1.计算属性最终会出现在vm上,直接读取使用即可。

​ 2.如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变。

let vm = new Vue({
        el: '#app',
        data: {
        fastName: 'xiao',
        lastName: 'tao'
        },
        computed: {
        fullName() {
        return this.fastName + ' - ' + this.lastName
        }
        }
 })

第一个 Vue-cli 项目

vue-cli 是官方提供的一个脚手架 用于快速生成一个vue 的项目模板

主要的功能:

  • 统一的目录结构
  • 本地调试
  • 热部署
  • 单元测试
  • 集成打包上线

需要的环境:

  • Node.js 官网下载

  • Git

  • 镜像 https://npm.taobao.org/mirrors/git-for-windows/

确认nodejs 是否安装成功

cmd

node -v # 查看是否能打印出版本号即可
npm -v  # 查看是否能打印出版本号即可

npm : 就是一个软件包管理工具 就和linux 下的apt 软件安装差不多

安装 Node.js 淘宝镜像加速器 (cnpm)

npm install cnpm -g   # -g 就是全局安装

# 或使用如下
npm install --registry=https://registry.npm.taobao.org

安装 vue-cli

cnpm install vue-cli -g

测试是否安装成功

查看可以基于哪些模板创建vue 通常选择 webpack

vue list  

创建第一个 vue-cli

cmd 去到一个文件夹 如 D:vue

vue init webpack myvue   # myvue 项目名

? Project name myvue
? Project description A Vue.js project
? Author xiaotao
? Vue build standalone
? Install vue-router? No
? Use ESLint to lint your code? No
? Set up unit tests Noc
? Setup e2e tests with Nightwatch? No
? Should we run `npm install` for you after the project has been created? (recommended) no

   vue-cli · Generated "myvue".

# Project initialization finished!
# ========================

To get started:

  cd myvue
  npm install (or if using yarn: yarn)
  npm run dev

Documentation can be found at https://vuejs-templates.github.io/webpack

初始化并运行:

cd myvue
npm install
npm run dev

打包成功访问

脚手架创建vue项目

vue create  项目名称

WebPack

安装打包工具

npm install webpack -g

npm install webpack-cli -g

# 删除
npm uninstall -g webpack
npm uninstall -g webpack-cli

测试安装成功

webpack -v 
webpack-cli -v

配置

创建webpack.config.js 配置文件

  • entry :入口文件 指定webpack用哪个文件作为项目的入口

  • output:输出 指定webpack把处理完成的文件放置到指定路径

  • module:模块 用于处理各种类型的文件

  • resolve:设置路径指向

  • piugins:插件 如:热更新 代码重用

  • watch:监听 用于设置文件改动后直接打包

  • 创建一个项目

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iiJTQxcZ-1689212938290)(Vue.assets/2021-10-06_163955.png)]

  • 创建一个名为modules 的目录 用于放置js模块

  • 在modules下创建模块文件 如 hello.js 用于编写js模块相关代码

    // 暴露一方法
    exports.sayHei = function(){
    	document.write('<h1>ES6 规范</h1>')
    };
    
    
  • 在modules下创建一个main.js 的入口文件 用于打包设置entry属性

    var hello = require('./hello');  // 类似于java 的导包 导入 hello.js
    hello.sayHei();
    
    
  • 在项目目录下创建webpack.config.js 配置文件

module.exports = {
	entry: 	'./modules/main.js', // 入口
	output: {
		filename: './js/bundle.js'    //输出到哪
	}
}

  • 使用 webpack 命令打包

    webpack  
    webpack --watch   # 类似于 idea 的热部署  实时更新
    
    

打包成功后:

  • 在项目目录下创建index.html 引入打包后的js

    <script src="dist/js/bundle.js"></script>
    
    

    运行

传值

父传子

使用 props 获取父传过来的值

data() {
        return {
            todo: [
                {
                    id: '001',
                    name: '吃饭',
                    status: true
                }
            ]
       }
 }

<template>
	<user-list :todo='todo' />
</template>

<div>
    {{ todo }}
</div>

 props: ['todo']

子传父

先在父类定义一个接收数据的方法 子类调用该方法传值给父类

<user-header :receive='receive' />

methods: {
        receive(x) {
            console.log('收到子组件的值',x)
        }
}

props: ['receive'],
// 子组件传值给父组件
this.receive(todo)

父传孙

data() {
        return {
            todo: [
                {
                    id: '001',
                    name: '吃饭',
                    status: true
                }
            ]
       }
 }

<template>
	<user-list :todo='todo' />
</template>

<template>
	<user-itme :todo='todo' />
</template>

props: ['todo']

 props: ['todo']

<div>
    {{ todo }}
</div>

自定义事件实现 子传父

方式一

<student @xiaotao="getStudentName" />

getStudentName(name) {
    console.log('学生姓名: '+ name);
}

<button @click="sendStudentName">把学生姓名给App</button>

sendStudentName() {
    // $emit 触发自定义事件
    // 触发 Student 组件实例上的 xiaotao 事件
    this.$emit('xiaotao', this.name);
}

方式二

<student ref='student'/>

mounted() {
    this.$refs.student.$on('xiaotao', this.getStudentName);
}

解绑事件

<button @click="unbind">解绑 xiaotao 事件</button>

unbind() {
    // $off 解绑自定义事件
    // 解绑 Student 组件实例上的 xiaotao 事件
    this.$off('xiaotao');
    // 解绑多个事件
    // this.$off(['xiaotao', 'xiaotao2']);
    // 解绑所有
    this.$();
}

给实例绑定原生事件

<student  @click.native="show" />

show() {
    console.log('点击了');
}

全局事件总线

任意组件间通信

image-20220615145854240

配置全局事件总线

new Vue({
      beforeCreate() {
        Vue.prototype.$bus = this    // 配置全局事件总线
      }
})

取值组件

mounted() {
    this.$bus.$on('xiaotao', (name) => {
        	console.log(name);
    });
},
    // 销毁自定义事件
    beforeDestroy() {
       	       this.$bus.$off('xiaotao');
    }

传值组件

sendStudentName() {
    	this.$bus.$emit('xiaotao', this.name);
}

信息订阅与发布

任意组件间通信

  • 订阅消息: 消息名
  • 发布消息: 消息内容

使用第三方库

pubsub.js

安装

npm i pubsub.js

引入

import PubSub from 'pubsub-js'

取数据

mounted() {
    this.pudid = PubSub.subscribe('xiaotao', (msg, data) => {
        console.log('有人发布了 '+ msg +' 消息, 消息回调执行了: '+data);
    });
},
    beforeDestroy() {
        PubSub.unsubscribe(this.pudid);
    }

提供数据

PubSub.publish('xiaotao', this.name);

$nextTick()

DOM 节点更新后执行

过渡与动画

Animate.css

Animate.css | A cross-browser library of CSS animations.

安装
npm install animate.css --save

导入

    import 'animate.css';

<transition-group 
                  name="animate__animated animate__bounce"
                  enter-active-class="animate__swing"
                  leave-active-class="animate__backOutUp"
                  appear>
    <h1 v-show="!isShow" key="1">hello</h1>    
    <h1 v-show="isShow" key="2">vue</h1>    
</transition-group>

vue axios

npm i axios

<template>
  <div>
      <button @click="getDept">获取部门信息</button>
  </div>
</template>

<script>
import axios from 'axios'
export default {
  name: "App",
  methods: {
    getDept() {
      axios.get('http://localhost:5000/').then(res => {
        console.log(res.data)
      }, err => {
        console.log(err)
      })
    }
  },
};
</script>

存在问题 跨域

image-20220616125631803

解决方式:

后端: cors nainx

前端:

代理服务器 vue-cli

配置 vue.config.js

devServer: {
    port: 8080,
    proxy: {
      '/api': {
        target: 'http://localhost:5000',
        changeOrigin: true,
        pathRewrite: {
          '^/api': ''       // 去掉路径中的api
        }
      }
    }
  }

修改请求

axios.get('http://localhost:8080/api')

image-20220616140333501

vue-resource

跟 axios 类似 是 vue 的一个插件库

npm i vue-resource

main.js

import vueResource from 'vue-resource'

Vue.use(vueResource)

插槽 slot

默认插槽

<template>
  <div class="container">
      <Category title="美食">
          <img src="https://avatars.githubusercontent.com/u/89018496?v=4" alt="" srcset="">
      </Category>
      <Category title="游戏">
          <ul>
            <li v-for="item in games" :key="item.id">{{item.name}}</li>
          </ul>
      </Category>
      <Category title="电影"></Category>
  </div>
</template>

<div class="category">
        <h3>{{title}}分类</h3>
        <slot>默认值如果组件不传值就会显示</slot>
    </div>

image-20220616153515346

具名插槽

<template>
  <div class="container">
      <Category title="美食">
          <img slot="center" src="https://avatars.githubusercontent.com/u/89018496?v=4" alt="" srcset="">
          <a slot="footer" href="https://xiaotao.cloud">更多美食</a>
      </Category>
      <Category title="游戏">
          <ul slot="center">
            <li v-for="item in games" :key="item.id">{{item.name}}</li>
          </ul>
          <template v-slot:footer>
            <a slot="footer" href="https://xiaotao.cloud">更多游戏</a>
            <h4>欢迎使用!</h4>
          </template>
      </Category>
      <Category title="电影">

      </Category>
  </div>
</template>

<div class="category">
        <h3>{{title}}分类</h3>
        <slot name="center">默认值如果组件不传值就会显示</slot>
        <slot name="footer">默认值如果组件不传值就会显示2</slot>
    </div>

image-20220616154807683

作用域插槽

数据在子类 都是要在父类遍历

<template>
  <div class="container">
    <Category title="游戏">
      <template scope="{games}">
        <ul>
          <li v-for="item in games" :key="item.id">{{ item.name }}</li>
        </ul>
      </template>
    </Category>
    <Category title="游戏">
      <template scope="{games}">
        <ol>
          <li v-for="item in games" :key="item.id">{{ item.name }}</li>
        </ol>
      </template>
    </Category>
    <Category title="游戏">
      <template scope="{games}">
        <h4 v-for="item in games" :key="item.id">{{ item.name }}</h4>
      </template>
    </Category>
  </div>
</template>

<template>
  <div class="category">
    <h3>{{ title }}分类</h3>
    <slot :games="games">默认值如果组件不传值就会显示</slot>
  </div>
</template>

image-20220616160849519

vuex

解决多组件共享数据问题

全局事件总线

image-20220616161502608

vuex

image-20220616161647691

使用

  • 多个组件依赖同一状态
  • 来自不同组件的行为需要变更同一状态

image-20220616165035633

安装

vue2 要使用 vuex@3

vue3 要使用 vuex@4

npm i vuex

image-20220616173524626

// 该文件用于创建 vuex 最核心的 store,并将其绑定到 Vue 实例上。

import Vue from 'vue'
// 引入 Vuex
import Vuex from 'vuex'
// 使用
Vue.use(Vuex)

// 用于响应组件中的动作
const actions = {}

// 用于操作数据
const mutations = {}

//用于储存数据
const state = {}

// 创建 并 暴露 store 实例
export default new Vuex.Store({
    state,
    actions,
    mutations
})

main.js

import store from './store'

new Vue({
  render: h => h(App),
  store,   
  beforeCreate() {
    Vue.prototype.$bus = this    // 配置全局事件总线
  }
}).$mount('#app')

然后就有:

image-20220616171307772

路由

vue-router

image-20220617093453310

是 vue的一个插件库, 专门用来实现 SPA 应用的

SPA 应用
  • 单页面 WEB 应用(Single page web application)
  • 整个应用只有 一个完整的页面
  • 点击页面中的导航链接, 只会 局部刷新
  • 数据需要通过 ajax 请求
路由
  1. 一个路由就是一组映射关系(key-value)
  2. key 为路径 value 可能是 function 或 component

安装

npm i vue-router@3                             # vue2
npm i vue-router@4                             # vue3

import VueRouter from 'vue-router'
Vue.use(VueRouter)

image-20220617105451461

具体看 github 提供的代码有详细讲解

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值