Vue2/3

vue基础

el:元素自动挂载(值可以选择是css选择器或DOM元素)el: ‘#app’
$mount:元素手动挂载(挂载到末尾),$mount('#app')
data:模型数据(值是一个对象)
methods:控制逻辑(值是函数)

组件化

date必须是一个函数,组件模板内容必须是单个根元素,模板内容可以使模板字符串用``包裹,组件名称使用驼峰式时只能在模板字符串中使用,在普通标签模板中必须用短横线式使用组件

  • 全局组件注册
Vue.component('组件名称', {
	date: function (){
		return {
			组件数据
		}
	},
	template: '组件模板内容'
})
  • 局部组件注册:在vue实例化对象里面添加一个component对象在对象内,局部组件只能在注册他的父组件内使用
var HelloWorld = {
	date: function (){
		return {
			组件数据
		}
	},
	template: '组件模板内容'
}
var vm = new Vue({
	el: 'app',
	data: {},
	component: {
		'HelloWorld': HelloWorld
	}
})
  • 组件传值
    • 子组件通过props[‘值’]接收父组件传值
Vue.component('组件名称', {
	props['title'],
	template: '{title}(组件模板内容)'
}) 
    • 父组件通过属性将值传递给子组件,props中使用驼峰,html中需要使用短横线方式,字符串形式模板中没有限制
<组件名称 title="来自父组件的数据"></组件名称>
<组件名称 :title="title1"></组件名称>(title1可以绑定到实例化vue对象的data中实现动态绑定)

插值表达式(将数据填充到html标签内,支持基本计算)

内容用法:{{表达式}}(支持js数据类型、运算符,三目运算符,短路原则,数组操作)

指令(自定义属性)

格式:v-开始

  1. v-cloak:解决插值表达式闪动问题(先隐藏,替换好值再显示)
  2. 添加css样式:[v-cloak]{displlay: none}
  3. 在插值表达式所在标签添加v-cloak
  4. 数据绑定指令:
  5. v-text:数据绑定,填充纯文本(相比插值表达式更简洁)
  6. v-html:数据绑定,填充html片段(存在安全问题容易导致xss攻击,本网站内部数据可以使用,第三方数据不可用)
  7. v-pre:数据绑定,填充原始信息(直接在标签内添加没有值,显示原始信息,跳过编译过程)
  8. 数据响应式(数据变化页面内容随之变化)
  9. 数据绑定:将数据填充到标签内
    • 双向数据绑定:视图界面数据发生变化,控制台信息也随之发生变化,v-model
      • v-model:双向数据绑定(绑定vue实例化对象data中的值)
  10. v-once:只编译一次(直接在标签内添加没有值,显示内容后不再具有响应式功能,可以节省性能)
    - MVVM设计思想:model代表模型、数据,view代表视图、模板、dom
  11. 自定义指令:
// 注册一个全局自定义指令 v-focus
Vue.directive('focus', {
  // 当被绑定的元素插入到 DOM 中时……
  inserted: function (el) {
    // 聚焦元素
    el.focus()
  }
})
// 局部指令,必须挂载到实例上和data平级
directives: {
  focus: {
    // 指令的定义
    inserted: function (el) {
      el.focus()
    }
  }
}
  1. 过滤器
Vue.filter('过滤器名称', function (value) {
  if (!value) return ''
  value = value.toString()
  return value.charAt(0).toUpperCase() + value.slice(1)
})
  1. 过滤器使用
    <div>{{数据 | 过滤器名称}}</div>
事件(函数)绑定
  1. v-on指令:v-on:click='事件'(类似行内式)
  2. v-on指令简写:@click='事件'
  3. 事件函数调用:
  4. 绑定函数名称:v-on:click='函数名'(事件函数第一个参数为事件对象)
  5. 调用函数:v-on:click='函数名()'(事件函数最后一个参数为事件对象,事件对象名称必须为$event)
  6. 事件修饰符:v-on:click.stop='事件'
  7. 阻止冒泡:.stop
  8. 阻止默认行为:.prevent
  9. 按键修饰符:v-on:keyup.enter='事件'
  10. 回车键:.enter
  11. 删除键:.delete
  12. 自定义按键修饰符:
  13. 全局config.keyCode对象:Vue.config.keyCode.f1 = 112
  14. 表单域修饰符:v-model.muber="数值"
  15. 转化为数值:.number
  16. 去除头尾空格:.trim
  17. input事件切换为change事件:.lazy(表单验证用户名常用)
属性绑定
  1. v-bind指令:v-bind:href='url',用法:<a v-bind:href='url'>跳转</a>
  2. v-bind指令简写::href='url',用法:<a :href='url'>跳转</a>
  3. v-model低层实现原理:<input v-bind: value = "msg" v-on: input = "msg = $event.target.value">
样式绑定
  1. class样式处理:
  2. 对象语法:v-bind:class='{属性: 值}'
  3. 数组语法:v-bind:class='[数组名, 数组名]'
  4. style样式处理:
  5. 对象语法:v-bind:style='{属性: 值}'
  6. 数组语法:v-bind:style='[数组名, 数组名]'
分支循环结构
  1. 分支结构:
    v-if(控制元素是否渲染到页面)
    v-else
    v-else-if
    v-show(控制元素是否显示)
  2. 循环结构:
  3. 遍历数组:v-for='item in 数组名'v-for='(item,索引) in 数组名'(使用{{item.key}}填充遍历数据)
  4. 遍历对象:v-for='(value, key, 索引) in object'v-if='value==12' v-for='(value, key, 索引) in object'(v-if和v-for结合使用)
  5. 绑定唯一标识帮助Vue区分不同元素提高性能::key='item.id'

API

  1. 修改响应式数据
  2. Vue.set(要处理数组名称, 要处理数据索引, 要处理数组值)
  3. vue.$set(要处理数组名称, 要处理数据索引, 要处理数组值)

模块化

传统开发模式问题:命名冲突,文件依赖
模块化:功能单独封装到模块(文件)中,模块相互隔离通过特定接口公开内部成员,也可依赖别的模块(方便代码复用,提高开发效率,方便后期维护)
48. 浏览器端模块化:
49. AMD:Rquire.js(https://requirejs.org/)
50. CMD:Sea.js(https://seajs.github.io/seajs/docs/)
51. 服务器端模块化:
52. commonJS:
- 模块分为单文件模块与包
- 模块成员导出:module.exports={}exports.变量名=() ={}
- 模块成员导入:require('模块标识符')
53. ES6模块化:浏览器和服务器通用模块化标准
- 每个js文件都是独立模块,导入模块成员使用import关键字,暴露模块成员使用exports关键字
- 体验:通过node.js中安装babel插件体验
- 安装依赖:npm install --save-dev @babel/core @babel/cli @babel/preset-env @babel/node
- npm install --save @babel/polyfill
- 根目录创建文件babel.config.js,文件代码如下

const presets = [
  ["@babel/env", {
      targets: {
        edge: "17",
        firefox: "60",
        chrome: "67",
        safari: "11.1",
      }
    }]
];
module.exports = { presets };
  1. 代码执行:npx babel-node index.js
  2. 默认导入导出:
    - 导出:exports default 导出成员
    - 导入:import 导出文件名称 from '导出文件路径'
  3. 按需导入导出:
    - 导出:exports let 变量名 = '值'
    - 导入:import {变量名, 变量名} from '导出文件路径'
  4. 直接导入并执行:import '执行文件路径'(只执行模块中代码,不暴露成员)

vue单文件

组件模板区:<template></template>
业务逻辑区:<script></script>
样式区:<style scoped></style>(添加scoped属性防止样式冲突)

vue-router

vuex:非关系组件之间共享数据方式

父向子传值:v-bind(属性绑定)props
子向父传值:v-on(事件绑定)$emit
59. 兄弟组件之间共享数据:EventBus或公共$emit
60. $on(接收数据组件)
61. $emit(发送数据组件)

vuex基本使用
  1. 安装依赖包:npm install vuex --save
  2. 导入依赖包
import Vuex from 'vuex'
vue.use(Vuex)
  1. 创建store对象:state中存放全局共享数据
const store = new Vuex.Store({
	state: {},
	mutations: {}
	Actions: {}
	Getter: {}
})
  1. store对象挂载到vue实例中
// 先导入
import store from './store' 
// 后挂载
new Vue({
	el:'#app',
	render: h => h(app),
	router,
	store
})
vuex核心概念
State: 提供唯一公共数据源,存储所有共享数据state: {key: value}
  1. 数据访问方式:this.$store.state.全局数据名称(this可省略)
  2. 数据访问方式:
  3. 从vuex中按需导入mapstate函数:import { mapState } from 'vuex'
  4. 通过函数将当前组件全局数据映射为computed计算属性:computed: {...mapState(['count'])}
Mutation:用于变更store中的数据,不允许直接操作store中的数据,使用commit触发Mutation函数,定义中step对应触发中step所填值
  1. 触发方式1
// 先定义
const store = new Vuex.Store({
	state: {
		count: 0
	},
	mutation: {
		add(state, step) {
			state.count++
    		state.count += step
		}
	}
})
// 后触发:在单文件中调用,使用step携带函数
methods: {
  handlel(){
    this.$store.commit('add', step)(触发mutation方式)
  }
}
  1. 触发方式2
  2. 从vuex中按需导入mapMutations函数:import { mapMutations } from 'vuex'
  3. 通过导入mapMutations函数将所需mutations函数映射为methods方法:methods: {...mapMutations(['add', 'addN'])}
Action:处理异步任务(通过异步操作变更数据必须Action而不能用Mutation,但变更数据要在Action中触发Mutation间接变更数据)
  1. 触发方式1
// 先定义:step接收出发时携带参数
const store = new Vuex.Store({
	actions: {
		addAsync (context, step) {
			setTimeout( () => {
				context.commit('add', step);
			}, 1000)
     	}
    }
})
// 后触发
mutations: {
	handle () {
		this.$store.dispatch('addAsync', 参数)(触发actions方式)
	}
}
  1. 触发方式2
  2. 从vuex中按需导入mapActions函数:import { mapActions } from 'vuex'
  3. 通过导入mapActions函数将所需actions函数映射为methods方法:methods: {...mapActions(['addAsync', 'addNAsync'])}
Getter:用于对store中数据处理形成新数据,store中数据变化getter数据随之变化
  1. 触发方式1
// 先定义
const store = new Vuex.Store({
	state:{
		count: 0
	},
	getters: {
		名称: state => {
			return '当前最新数量是'+ state.count
		}
	}
})
// 后触发
this.$store.gstters.名称
  1. 触发方式2
  2. 从vuex中按需导入mapActions函数:import { mapGetters } from 'vuex'
  3. 通过导入mapActions函数将所需actions函数映射为methods方法:computed: {...mapGetters(['addAsync'])}
Module:拆分vuex中的数据、更新、操作,分解为一个个模块便于维护
  1. 获取方式1
// 先定义
const store = new Vuex.Store({
	module: {
	user: {
		namespaced: true, //防止通过全局`this.$store.commit('count')`调用vuex中的模块,必须`this.$store.commit('user/count')`,映射也类似,或者在组件中建立一个方法,在方法内部封装this['user/count']()
		state: {
			count: 0
		},
		mutation: {
			add(state, step) {
				state.count++
				state.count += step
			}
		},
	setting: {
		state: {
			count: 0
		},
		mutation: {
			add(state, step) {
				state.count++
				state.count += step
			}
		}
	}
})
// 后获取
使用组件中获取方式`$store.state.模块名.属性名`
  1. 获取方式2
  2. 在根级别getters中定义:属性名: state => state.模块名.属性名',在使用组件中computed: {...mapGetters(['属性名', '属性名'])}
  3. 创建基于某个命名空间辅助函数:createnamespacedHelpers
    - 先引入import { mapGetters, createnamespacedHelpers } from 'vuex' const{ mapMutations } = createnamespacedHelpers('user')
    - 使用methods: {...mapActions(['count'])} 点击调用 <button @click="count"> </button>

vue脚手架(快速生成vue项目基本架构,https://cli.vuejs.org/zh/)

安装3.x版本:npm install -g @vue/cli
查看脚手架安装完成与否及版本号:vue -V
86. 创建Vue项目:
87. 基于交互式命令行的方式,创建新版vue项目:vue create project
88. 基于图形化界面的方式,创建新版vue项目:vue ui
- 必选功能:Babel,Router,Linter/Formatter(ESLint+Standard config,Lint on save),使用配置文件
89. 基于2.x的旧模板,创建旧版vue项目:
- npm install -g @vue/cli-init
- vue init webpack my-project
90. 自定义配置
91. 通过package.json配置

"vue":{
	"devServer":{
		"port":8888,
		"open":true
	}
}
  1. 通过单独的配置文件配置项目
    - 在项目的跟目录创建文件 vue.config.js
    - 在vue.config.js文件中进行相关配置,从而覆盖默认配置
module.exports = {
	devServer: {
		//自动打开浏览器
		open:true
		//配置端口号
		port: 8888
	}
}

axios使用

  1. 终端安装axios包
    npm i axios
  2. 在main.js中引入axios
    import axios from 'axios
  3. 设置请求的根路径
    axios.defaults.baseURL = 'http://127.0.0.1:8888/api/private/v1/'
  4. 将axios包挂载到vue的原型对象上,使得vue的每一个组件能够通过this访问$http,从而发起ajax请求
    Vue.prototype.$http = axios
  5. 通过$http.post发起请求login 为请求路径,后面的为请求需要携带的参数,其返回值为promise对象包含的数据很多,通过await简化promise,awai只能用在async修饰的方法中,返回的是具体的响应对象data{},其中有六个属性都是axios封装好的,属性中只有data属性是服务器返回的真实数据。
    const res = await this.$http.post('login',this.loginForm)
  6. 通过判断服务器响应的status,做出消息提示
if (res.data.meta.status!=200) return this.$message.error('登录失败');
this.$message.success('登录成功')

实操步骤

前端技术栈:Vue2/3、Vue-router、Element-UI、Axios、Echarts
后端技术栈:Node.js、Express、Jwt、Mysql、Sequelize

  • 前端项目初始化:
    • 安装Vue脚手架
    • 通过Vue脚手架创建项目
    • 配置Vue路由
    • 配置Element-UI组件库
    • 配置axios库
    • 初始化git远程仓库
    • 本地项目托管Github中
  • 后台项目环境配置:
    • 安装MySQL数据库
    • 安装Node.js环境
    • 配置项目相关信息
    • 启动项目
    • 使用Postman测试后台项目接口是否正常

vue2

生命周期

beforeCreate()-创建前
created()-创建后(常用,开始请求)
beforeMount()-载入前
mounted()-载入后(开始操作dom)
beforeUpdate()-更新前
updated()-更新后
beforeDestory()-销毁前(释放vue以外资源,如清除定时器、延时器)
destoryed()-销毁后

响应式原理

var book = {
    _year : 2004,
    edition : 1
}
book.year = 2005;
利用原生Object.defineProperty方法
Object.defineProperty(book,"year",{
    get(){ //访问book对象中year属性时自动调用的方法,返回值就是拿到的值
        return this._year
    },
    set(newYear){ //设置book对象中year属性时自动调用的函数,属性最新值会当成实参传入
        this._year = newYear;
    }
})

获取单个元素

通过ref属性绑定该元素
<div ref="box"></div>
通过this.$refs.box获取元素

获取v-for便利的多个元素

通过ref属性绑定被遍历元素
<li v-for="i in 4" :key="i" ref="li"></li>
通过this.$refs.li获取所有遍历元素

除去v-model实现双向数据绑定的另外方式

<Son :money='money' @updata:money="fn" />简写<Son :money.sync='money' />
v-modul.sync已经合并成v-modul指令

语法糖

<c :value="msg" @input="msg=$event" />

mixins语法(vue2中解决逻辑代码冲突问题,vue3组合API解决了问题不推荐使用)

混入(mixin)提供一种灵活的方式来分发vue组件中的可复用功能,一个混入对象可以包含任意组件选项,组件使用混入对象是,所有混入对象的选项将混合进入该组件本身选项中
在main.js中app实例挂在前app.maxin({//可以按照组件setup内容写入)}
模块化之后在模块中暴露出去,使用时在需要使用的组件中import导入,写入mixins: []与components同级,因为可能不止写入一个逻辑

vue3

生命周期

setup()-创建实例前,创建data和method,新的组件选项,组合API的起点,在vue2的beforeCreate前执行,此时this不是组件实例而是undefined,在模板中使用的数据和函数在setup中返回
onBeforeMount()-挂载DOM前
onMounted()-挂载DOM后
onBeforeUpdate()-更新前
onUpdated()-更新后
onBeforeUnmount()-卸载前
onUnmounted()-卸载后
onActivated()-被包含在 中的组件,多出两个生命周期钩子函数,激活时
onDeactivated()-组件切换,切换组件消失执行
onErrorCaptured()-子孙组件异常时

响应式原理

var book = {
    _year : 2004,
    edition : 1
}
book.year = 2005;
let proxy = new Proxy(obj, {
  get : function (target, prop) {
    return target[prop]
  },
  set : function (target, prop, value) {
    target[prop] = value;
    if(prop === 'count') {
      double = getDouble(value)
    }
  },
  deleteProperty(target, prop) {
    delete target[prop]
    if(prop === 'count') {
      double = NaN
    }
  }
})

ref函数:定义简单类型数据也可以定义复杂数据类型,成为响应式数据(重点)

// 先导入函数
import { ref } from 'vue'
// 后定义函数
const obj = ref('ls')
// 使用,修改值需要.value
obj.value

ref属性:获取DOM或组件实例

  • 获取单个DOM或组件**

    • 先使用ref定义一个空的响应式数据
      const dom = ref(null)
    • setup中返回该数据,想要获取dom元素在该元素上使用ref属性绑定该数据即可
      <div ref="dom"></div>
  • 获取v-for遍历的DOM或组件

    • 定义一个空数组接受所有li
      const domList = []
    • 定义一个函数,网空数组pushDOM
const setDom = (el) => {
	domList.push(el)
}

reactive函数:只能定义复杂类型数据,成为响应式数据(重点)

// 先导入函数
import { reactive } from 'vue'
// 后定义函数
const obj = reactive({
	name: 'ls',
})
// 使用
obj.name

toRef函数:转换响应式对象中某个属性为单独响应式数据,并且值关联(解构数据不能实现响应式)

// 先导入函数
import { reactive, toRef } from 'vue'
// 后定义函数
`const name = toRef(obj, 'name')`
// 使用,toRef修改数据需要添加value,value是存放值的地方
name.value = 'zs'

toRefs函数:转换响应式中所有属性为响应式数据,用于解构|展开reactive定义对象

// 先导入函数
import { reactive, toRef } from 'vue'
// 后定义函数,转化之后可以返回解构出的对象
const obj1 = toRefs(obj)`
// 使用,toRefs修改数据需要添加value,value是存放值的地方
// 与reactive函数定义数据相通`obj.name = 'zs'`也可以
obj1.name.value = 'zs'

Vue3语法糖

<Son :modelValue="msg" @update:modelValue="msg=$event" />
vue3封装组件支持v-model的时候父传子:modelValue子传父@update:modelValue

  • 想获取原生事件对象

    • 绑定是函数fn,fn(e){ //e就是事件对象}
    • 绑定是js表达式,提供一个默认变量 $event
      <h1 @click="$event.target.style.color='red'">父组件 {{count}}</h1>
  • 想获取自定义事件

    • 绑定是函数fn,fn(data){ //data是触发自定义事件的传参}
    • 绑定是js表达式,$event代表触发自定义事件的传参
      <Son :modelValue="count" @update:modelValue="count=$event" />

步骤

  1. 在main.js中导入createApp函数
    import {createApp} from 'vue'
  2. 定义App.vue根组件,导入main.js
    import App from './App.vue'
  3. 使用createApp函数基于App.vue组件创建应用实例
    const app = createApp(App)
  4. 挂载至index.html的#app容器
    app.mount('#app')

vue2/3

区别

vue2:选项(Options)API(易于学习和使用,但是代码组织性差)
vue3:组合(composition)API(体积小,性能提升,更好支持TS)

响应式对比

vue2响应式原理:通过Object.defineProperty()对属性的读取、修改进行拦截(数据劫持)
vue3响应式原理:通过Proxy(代理)拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等

computed函数:定义计算属性,不能修改

// 基础用法
const obj = computed( () => {
	return 计算值
})
// 高级用法:支持v-model修改数据
const obj = computed( () => {
	get(){ // 获取计算属性值
		return 计算值 // 效果和基础用法相同
	}
	set(value) { // 监听计算属性变化
		age.value = value + 2
	}
})

watch函数:定义侦听器

监听ref和reactive定义的响应式数据

data: {}
watch: {
	// 简单写法
	数据属性名(newVal, oldVal){
		this.key = newVal
	}
	'对象.属性名'(newVal, oldVal){
		this.key = newVal
	}
	// 完整写法
	数据属性名: {
		deep: true, // 是否对复杂类型深度监视
		immediate: true, // 是否组件初始化立刻执行一次handler方法
		handler(newVal, oldVal){
			this.key = newVal
		}
	}
}
watch(count, (newVal, oldVal) => {}, {deep: true, immediate: true})

watch(count, (newVal, oldVal) => {}, {deep: true, immediate: true})第一个参数是需要监听的对象,第二个参数是改变后触发的函数,第三个参数是个对象,可以设置deep深度监听数据变化和immediate默认执行
监听多个数据变化
watch([count, obj], (newVal, oldVal) => {})
监听对象中某个属性变化需要写成函数返回该属性的方式
watch(() => obj.name, (newVal, oldVal) => {})

父子通讯

父传子
父组件定义一个ref数据,使用return返回并使用属性绑定到父组件中的子组件占位符上:money="导出ref对象"
子组件中使用props接收父组件数据,props和setup同级且setup(props)中的props就是父组件数据
子传父
触发自定义事件的时候emit来自setup(props, {emit}){//emit就是触发事件函数}
<Son :money="money" @updata:money="updataMoney" />简写<Son v-modul:money='money' />

非父子通讯

  • event bus事件总线:非父子组件之间简单消息传递
// 创建一个都能访问到的实践总线(空vue实例)
// utils/EventBus.js
import Vue from 'vue'
const Bus = new Vue()
export default Bus
// A组件(接收方)监听Bus实例的事件
created(){
	Bus.$on('sendMsg', () => {
		this.msg = msg
	})
}
// B组件(发送方)触发Bus实例的事件
Bus.$emit('sendMsg','这是一个消息')
  • vuex:非父子组件之间简单消息传递

依赖注入:后代组件通讯(单向数据流)

父组件使用provide('约定接收名称', 父组件传递数据对象名或函数名)
子孙组件使用inject('约定接收名称')

vue踩坑

TypeError: Cannot read properties of undefined (reading ‘_withTask‘)
类型错误:无法读取未定义的属性(读取“ with Task ”)
_withTask在vue的源码中表示编译错误,例如使用了一个未定义的方法,在组件中使用@定义了一个方法,在methods中没有定义该方法就会出现该错误

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值