el:元素自动挂载(值可以选择是css选择器或DOM元素)el: ‘#app’
$mount
:元素手动挂载(挂载到末尾),$mount('#app')
data:模型数据(值是一个对象)
methods:控制逻辑(值是函数)
vue生命周期
beforeCreate:创建前
created:创建后
beforeMount:载入前
mounted:载入后
beforeUpdate:更新前
updated:更新后
beforeDestory:销毁前
destoryed:销毁后
vue2响应式原理:
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;
}
})
插值表达式(将数据填充到html标签内,支持基本计算)
内容用法:{{表达式}}(支持js数据类型、运算符,三目运算符,短路原则,数组操作)
指令用法
指令(自定义属性)
格式:v-开始
- v-cloak:解决插值表达式闪动问题(先隐藏,替换好值再显示)
- 添加css样式:[v-cloak]{displlay: none}
- 在插值表达式所在标签添加v-cloak
- 数据绑定指令:
- v-text:数据绑定,填充纯文本(相比插值表达式更简洁)
- v-html:数据绑定,填充html片段(存在安全问题容易导致xss攻击,本网站内部数据可以使用,第三方数据不可用)
- v-pre:数据绑定,填充原始信息(直接在标签内添加没有值,显示原始信息,跳过编译过程)
- 数据响应式(数据变化页面内容随之变化)
- 数据绑定:将数据填充到标签内
-双向数据绑定:视图界面数据发生变化,控制台信息也随之发生变化,v-model- v-model:双向数据绑定(绑定vue实例化对象data中的值)
- v-once:只编译一次(直接在标签内添加没有值,显示内容后不再具有响应式功能,可以节省性能)
- MVVM设计思想:model代表模型、数据,view代表视图、模板、dom
- 数据绑定:将数据填充到标签内
- 自定义指令:
// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
// 局部指令,必须挂载到实例上和data平级
directives: {
focus: {
// 指令的定义
inserted: function (el) {
el.focus()
}
}
}
- 过滤器
Vue.filter('过滤器名称', function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})
- 过滤器使用
<div>{{数据 | 过滤器名称}}</div>
事件(函数)绑定
- v-on指令:
v-on:click='事件'
(类似行内式) - v-on指令简写:
@click='事件'
- 事件函数调用:
- 绑定函数名称:
v-on:click='函数名'
(事件函数第一个参数为事件对象) - 调用函数:
v-on:click='函数名()'
(事件函数最后一个参数为事件对象,事件对象名称必须为$event)
- 绑定函数名称:
- 事件修饰符:
v-on:click.stop='事件'
- 阻止冒泡:
.stop
- 阻止默认行为:
.prevent
- 阻止冒泡:
- 按键修饰符:
v-on:keyup.enter='事件'
- 回车键:.enter
- 删除键:.delete
- 自定义按键修饰符:
- 全局config.keyCode对象:
Vue.config.keyCode.f1 = 112
- 全局config.keyCode对象:
- 表单域修饰符:
v-model.muber="数值"
- 转化为数值:
.number
- 去除头尾空格:.trim
- input事件切换为change事件:.lazy(表单验证用户名常用)
- 转化为数值:
属性绑定
- v-bind指令:
v-bind:href='url'
,用法:<a v-bind:href='url'>跳转</a>
- v-bind指令简写:
:href='url'
,用法:<a :href='url'>跳转</a>
- v-model低层实现原理:
<input v-bind: value = "msg" v-on: input = "msg = $event.target.value">
样式绑定
- class样式处理:
- 对象语法:
v-bind:class='{属性: 值}'
- 数组语法:
v-bind:class='[数组名, 数组名]'
- 对象语法:
- style样式处理:
- 对象语法:
v-bind:style='{属性: 值}'
- 数组语法:
v-bind:style='[数组名, 数组名]'
- 对象语法:
分支循环结构
- 分支结构:
v-if(控制元素是否渲染到页面)
v-else
v-else-if
v-show(控制元素是否显示) - 循环结构:
- 遍历数组:
v-for='item in 数组名'
或v-for='(item,索引) in 数组名'
(使用{item}填充遍历数据) - 遍历对象:
v-for='(value, key, 索引) in object'
或v-if='value==12' v-for='(value, key, 索引) in object'
(v-if和v-for结合使用) - 帮助Vue区分不同元素提高性能:
:key='item.id'
- 遍历数组:
API
- 修改响应式数据
Vue.set(要处理数组名称, 要处理数据索引, 要处理数组值)
vue.$set(要处理数组名称, 要处理数据索引, 要处理数组值)
模块化
传统开发模式问题:命名冲突,文件依赖
模块化:功能单独封装到模块(文件)中,模块相互隔离通过特定接口公开内部成员,也可依赖别的模块(方便代码复用,提高开发效率,方便后期维护)
- 浏览器端模块化:
- AMD:Rquire.js(https://requirejs.org/)
- CMD:Sea.js(https://seajs.github.io/seajs/docs/)
- 服务器端模块化:
- commonJS:
- 模块分为单文件模块与包
- 模块成员导出:module.exports和exports
- 模块成员导入:require(‘模块标识符’)
- commonJS:
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 };
- 代码执行:
npx babel-node index.js
- 默认导入导出:
- 导出:
exports default 导出成员
- 导入:
import 导出文件名称 from '导出文件路径'
- 导出:
- 按需导入导出:
- 导出:
exports let 变量名 = '值'
- 导入:
import {变量名, 变量名} from '导出文件路径'
- 导出:
- 直接导入并执行:
import '执行文件路径'
(只执行模块中代码,不暴露成员)
Vue单文件
组件模板区:template
业务逻辑区:script
样式区:style(添加scoped属性防止样式冲突)
Vue脚手架(快速生成vue项目基本架构,https://cli.vuejs.org/zh/)
安装3.x版本:npm install -g @vue/cli
查看脚手架安装完成与否及版本号:vue -V
- 创建Vue项目:
- 基于交互式命令行的方式,创建新版vue项目:vue create project
- 基于图形化界面的方式,创建新版vue项目:vue ui
- 必选功能:Babel,Router,Linter/Formatter(ESLint+Standard config,Lint on save),使用配置文件
- 基于2.x的旧模板,创建旧版vue项目:
- npm install -g @vue/cli-init
- vue init webpack my-project
- 自定义配置
- 通过package.json配置
"vue":{
"devServer":{
"port":8888,
"open":true
}
}
- 通过单独的配置文件配置项目
- 在项目的跟目录创建文件 vue.config.js
- 在vue.config.js文件中进行相关配置,从而覆盖默认配置
module.exports = {
devServer: {
//自动打开浏览器
open:true
//配置端口号
port: 8888
}
}
实操
前端技术栈:Vue、Vue-router、Element-UI、Axios、Echarts
后端技术栈:Node.js、Express、Jwt、Mysql、Sequelize
- 前端项目初始化:
- 安装Vue脚手架
- 通过Vue脚手架创建项目
- 配置Vue路由
- 配置Element-UI组件库
- 配置axios库
- 初始化git远程仓库
- 本地项目托管Github中
- 后台项目环境配置:
- 安装MySQL数据库
- 安装Node.js环境
- 配置项目相关信息
- 启动项目
- 使用Postman测试后台项目接口是否正常
vue-router:
vuex:非关系组件之间共享数据方式
父向子传值:v-bind(属性绑定)props
子向父传值:v-on(事件绑定)$emit
- 兄弟组件之间共享数据:
EventBus
或公共$emit
$on
(接收数据组件)$emit
(发送数据组件)
Vuex基本使用
- 安装依赖包:
npm install vuex --save
- 导入依赖包
import Vuex from 'vuex'
vue.use(Vuex)
- 创建store对象:state中存放全局共享数据
const store = new Vuex.Store({
state: {
},
mutations: {
}
Actions: {
}
Getter: {
}
})
- store对象挂载到vue实例中
import store from './store'
new Vue({
el:'#app',
render: h => h(app),
router,
store
})
Vuex核心概念:
State: 提供唯一公共数据源,存储所有共享数据state: {key: value}
- 数据访问方式:
this.$store.state.全局数据名称
(this可省略) - 数据访问方式:
- 从vuex中按需导入mapstate函数:
import { mapState } from 'vuex'
- 通过函数将当前组件全局数据映射为computed计算属性:
computed: {...mapState(['count'])}
- 从vuex中按需导入mapstate函数:
Mutation:用于变更store中的数据,不允许直接操作store中的数据,使用commit
触发Mutation函数,定义中step对应触发中step所填值
- 触发方式
- 先定义:
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方式)
}
}
- 触发方式:
- 从vuex中按需导入mapMutations函数:
import { mapMutations } from 'vuex'
- 通过导入mapMutations函数将所需mutations函数映射为methods方法:
methods: {...mapMutations(['add', 'addN'])}
- 从vuex中按需导入mapMutations函数:
Action:处理异步任务(通过异步操作变更数据必须Action而不能用Mutation,但变更数据要在Action中触发Mutation间接变更数据)
- 触发方式
- 先定义:step接收出发时携带参数
const store = new Vuex.Store({
actions: {
addAsync (context, step) {
setTimeout( () => {
context.commit('add', step);
}, 1000)
}
})
- 后触发:
mutations: {
handle () {
this.$store.dispatch('addAsync', 参数)(触发actions方式)
}
}
- 触发方式:
- 从vuex中按需导入mapActions函数:
import { mapActions } from 'vuex'
- 通过导入mapActions函数将所需actions函数映射为methods方法:
methods: {...mapActions(['addAsync', 'addNAsync'])}
- 从vuex中按需导入mapActions函数:
Getter:用于对store中数据处理形成新数据,store中数据变化getter数据随之变化
- 触发方式
- 先定义:
const store = new Vuex.Store({
state:{
count: 0
},
getters: {
名称: state => {
return '当前最新数量是【'+ state.count +'】
}
}
})
-
后触发:触发方式
this.$store.gstters.名称
-
触发方式:
- 从vuex中按需导入mapActions函数:
import { mapGetters } from 'vuex'
- 通过导入mapActions函数将所需actions函数映射为methods方法:
computed: {...mapGetters(['addAsync'])}
- 从vuex中按需导入mapActions函数:
Module:拆分vuex中的数据、更新、操作,分解为一个个模块便于维护
- 获取方式
- 先定义:
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.模块名.属性名
-
获取方式:
- 在根级别getters中定义:
属性名: state => state.模块名.属性名'
,在使用组件中computed: {...mapGetters(['属性名', '属性名'])}
- 在根级别getters中定义:
-
创建基于某个命名空间辅助函数:
createnamespacedHelpers
- 先引入
import { mapGetters, createnamespacedHelpers } from 'vuex'
const{ mapMutations } = createnamespacedHelpers(‘user’) - 使用
methods: {...mapActions(['count'])}
点击调用<button @click="count"> </button>
- 先引入
vue中使用axios
1.在main.js中引入axios
import axios from 'axios
2.设置请求的根路径
axios.defaults.baseURL = ‘http://127.0.0.1:8888/api/private/v1/’
3.将axios包挂载到vue的原型对象上,使得vue的每一个组件能够通过this访问$http,从而发起ajax请求.
Vue.prototype. h t t p = a x i o s 4. / / 通过 http = axios 4.//通过 http=axios4.//通过http.post发起请求login 为请求路径,后面的为请求需要携带的参数,其返回值为promise对象包含的数据很多
// 通过await简化promise,awai只能用在async修饰的方法中,返回的是具体的响应对象data{},其中有六个属性都是axios封装好的,属性中只有data属性是服务器返回的真实数据。
const res =await this.$http.post(‘login’,this.loginForm);
5.通过判断服务器响应的status,做出消息提示
if (res.data.meta.status!=200) return this. m e s s a g e . e r r o r ( ′ 登录失 败 ′ ) ; t h i s . message.error('登录失败'); this. message.error(′登录失败′);this.message.success(‘登录成功’)
<!-- 组件化(date必须是一个函数,组件模板内容必须是单个根元素,模板内容可以使模板字符串用``包裹,组件名称使用驼峰式时只能在模板字符串中使用,在普通标签模板中必须用短横线式使用组件) -->
<!-- 全局组件注册
Vue.component('组件名称', {
date: function (){
return {
组件数据
}
},
template: '组件模板内容'
}) -->
<!-- 局部组件注册:在vue实例化对象里面添加一个component对象在对象内,局部组件只能在注册他的父组件内使用
var HelloWorld = {
date: function (){
return {
组件数据
}
},
template: '组件模板内容'
};
var HelloWorld1 = {
date: function (){
return {
组件数据
}
},
template: '组件模板内容'
};
var vm = new Vue({
el: 'app',
data: {
},
component: {
'HelloWorld': HelloWorld,
'HelloWorld1': HelloWorld,
}
}); -->
<!-- 子组件通过props['值']接收父组件传值
Vue.component('组件名称', {
props['title'],
template: '{title}(组件模板内容)'
}) -->
<!-- 父组件通过属性将值传递给子组件,props中使用驼峰,html中需要使用短横线方式,字符串形式模板中没有限制
<组件名称 title="来自父组件的数据"></组件名称>
<组件名称 :title="title1"></组件名称>(title1可以绑定到实例化vue对象的data中实现动态绑定) -->