基本结构
const vm = new Vue({
data(){
return {}
},
watch:{},
computed:{},
methods:{},
filters:{},
components:{}
})
vm 即是Vue实例对象
vm.$el vue实例所挂载的元素
vm.$options vue自定义的属性和方法
vm.$data vue实例中的data属性
vue响应式原理
响应式: 即数据发生改变,界面自动发生刷新
1、考虑vue内部如何知道哪些数据发生了改变
2、考虑vue内部如何知道通知哪些地方更新界面
当创建vue实例、向Vue对象options中传入data对象后,vue内部会拿到这个data对象
const app = new Vue({
el:'',
data:{}
});
let obj = ..vue内部拿到的data对象
vue内部拿到data对象后使用Object.keys获取到data对象中的所有key,并通过循环遍历的方式根据key取出每一个属性。此时为了监听到每个属性的改变,使用Object.defineProperty为对象重新定义属性,并在Object.defineProperty的第三个属性中重写set、get方法,
Object.keys(obj).forEach(key=>{
let value = obj[key];
Object.defineProperty(obj,key,{
set(newValue){
value = newValue;
},
get(){
return value;
}
});
});
当改变vue中data中的数据时,即会执行set方法,使用、获取vue中data中的数据时,即会执行get方法。vue内部会解析html获取出哪里使用了该属性。使用该属性的地方必定会调用一次get方法,所以vue又使用了发布观察者模式,新建发布者对象,该对象管理着一个空的观察者数组,并且有添加观察者addSub、更新notify的方法,在每个属性的get方法中新建一个观察者对象,这样实现每使用一次该属性、即会新建一个观察者,并且将其加入到订阅者管理的数组中,这样某个属性发生改变,直接调用订阅者的notify方法,而订阅者的notofy方法中,会便利当前所有的观察者 使其调用观察者自身的update方法。
//订阅者对象
class Dep{
constructor(){
this.subs=[];
}
addSub(watcher){
this.sub.push(watcher);
}
notify(){
this.subs.forEach(item=>{
item.update();
})
}
}
//观察者对象
class Watcher{
constructor(name){
this.name=name;
}
update(){
...
}
}
....
Object.defineProperty(obj,key,{
set(newValue){
value = newValue;
}
get(){
new Watcher(...);
return value;
}
});
el
当前vue实例管控的区域
data
子组件中data必须为函数 为了彼此有一个独立作用域 不相互关联产生影响
computed
计算属性有缓存 如果相关的数据不发生改变 则当前计算属性就不会重新执行
计算属性赋值
data(){
return {
x:''
}
},
computed:{
nameFull:{
set(value){
this.x = value;
},
get(){
return this.x
}
}
}
计算属性传参
computed:{
listFull(){ // 闭包方式
return function(str){
return ...
}
}
}
methods
methods没有缓存 使用一次就会调用一次执行一次
watch
==普通监听
监听数据改变
watch:{
name(newV,oldV){
newV就是改变后的值
}
}
==深度监听
监听对象时,如果改变对象内的属性 监听不起效果 需要写成深度监听形式
写成对象形式 逻辑在handler函数中处理 增加deep:true属性
data:{
obj:{
name:'jnn'
}
},
watch:{
obj:{
handler(newV,oldV){
...
},
deep:true.
immediate:true// 是否监听后立即执行一次
}
}
过滤器filters
<span>{{name | filterName(参数)}}</span>
filters:{
filterName(str,arg1){
str 即为name的值
arg1 即为参数
return str+arg1;
}
}
插槽 slot
子Test:<div>
<slot name="slotName" a="a" b="b"></slot>
</div>
父:<Test>
<span slot="slotName" slot-scope="data">
{{data.a}}--{{data.b}}
</span>
</Test>
组件components
子组件data是一个函数并返回一个对象
因为组件是需要复用的,复用的时候会有自己得逻辑,
每个组件需要保存自己独立的状态,所以需要每个组件返回独立的对象
如果不返回对象 组件间会相互影响
混入mixins
新建混入文件mixins.js并导出一个对象,
对象中可以写vue实例中的任何属性data、methods、生命周期。。。
在组件中导入混入文件
import mixins from './mixins.js'
使用mixins声明 是一个数组
mixins:[mixins]
此时组件中就会有混入对象中的内容
混入对象中内容会和组件中内容混合
先执行混入对象中内容、再执行组件内
b u s 、 bus、 bus、on传递事件
main.js:
Vue.prototype.$bus = new Vue();//挂载
子组件中发出事件:
this.$bus.$emit(' 事件名 ')
父组件A中监听事件:
this.$bus.$on(' 事件名 ', function(){
。。。。
})
父组件B中监听事件:
this.$bus.$on(' 事件名 ', function(){
。。。
})
当一个组件发出事件,多个组件接收,
如果此时在父组件a中,那么父组件b中的接收会变得无意义,
所以父组件b失去活跃状态时可以关闭监听
this.$bus.$off();//不写事件名 会全部关闭
this.$bus.$off( ' 事件名 ',取消的事件函数) //关闭监听某一个事件
注意:
若同一个事件,经过不同父组件更改某一个数据会有bug,
应该在接收事件之前先 $off
this.$bus.$off(' 事件名 ' ).$on(' 事件名 ',function(){
。。。
})
样式相关
通过变量控制css样式
根据变量值变化决定是否绑定一个类样式,再在css样式中绑定这个类样式下的元素样式
<div class="l" :class="{ nightClass: isNightMode }">
夜间模式
</div>
/* 夜间模式时 图标变颜色 */
.bgSwitch .l.nightClass::before {
color: orangered;
}
使用less
普通使用:
vue-cli2:
1、安装less less-loader npm install less less-loader --save-dev
2、在webpack.config.js中配置rules
{
test:/\.less$/,
loader:'style-loader!css-loader!less-loader'
}
3、vue文件中:
<style lang='less'>
....
</style>
若报错 less-loader版本过高 改为 5.x.x
vue-cli3:
1、安装 npm install less less-loader --save-dev
2、vue文件中使用lang声明 lang = 'less'
引入全局less文件
直接全局引入less文件会报错 官方给出方法使用 style-resources-loader
vue-cli2:
1、安装: npm install less less-loader style-resources-loader --save-dev
2、配置 build/utils:
在 generateLoaders 函数中添加以下代码
if (loader == 'less') {
loaders.push({
loader: 'style-resources-loader',
options: {
patterns: [
path.resolve(__dirname, '../src/assets/less/base.less')
]
}
})
}
npm run dev 即可使用
vue-cli3:
1、执行命令 vue add style-resources-loader
选择需要的less语言 会自动生成vue.config.js 并自动配置好style-resources-loader
2、在vue.config.js中配置需要全局引入的less文件
vue.config.js:
const path = require('path');
module.exports = {
pluginOptions: {
'style-resources-loader': {
preProcessor: 'less',
patterns: [
path.resolve(__dirname, './src/assets/less/base.less')
]
}
}
}
过渡动画transition
首先使用transition组件包裹需要做动画的部分
<transition>
...
</transition>
然后定义动画各阶段做什么样式
如果transition不写name属性 使用默认.v-xxxx形式
如果transition定义name属性 使用 .name值-xxx.xxx形式
eg:
html:
<transition name="test">
<span>测试</span>
</transition>
style:
.test-enter{
...
}
.test-enter-active{
transition:all 2s;
}
vue过渡动画有四个状态
v-enter
v-enter-to
v-leave
v-leave-to
本地数据相关
本地模拟数据时候 获取图片
当自己模拟数据数据时候,无法获取assets/images中图片,
需要使用require或import导入图片
==普通图片格式:
1、{ imgPath:require('@/assets/images/.....png')}
2、import imga from '@/assets/images/....png';
{ imgPath : imga }
==webp图片格式
当图片为webp格式,需要借用file-loader导入
在配置loader处加上 file-loader的配置
{ test : /\.webp$/i, use:'file-loader' }
路由
动态加载路由
动态添加路由
前端管理路由方式:
1、登录后通过token再去获取当前用户的权限列表
或登录后后台直接返回权限列表
2、将权限列表保存vuex和localstorage中 在router/index中 先初始化共同的路由
再遍历vuex中权限列表,根据后台传回的权限列表路径和本地管理的路由对象形成映射
根据权限列表中路径加载不同的路由对象
3、router/index中创建方法 用于初始化动态加载的路由 根据权限遍历加载路由后将404路由通过数组的conca追加进去 不要一开始配置404路由 会出现刷新找不到界面的问题 将此方法分别在登陆成功后和在App.vue中的created方法中调用 用于登录后初始化动态路由和刷新浏览器再次初始化动态路由 防止刷新浏览器界面消失
// 初始化路由
export function initRouter() {
let currentRoutes = router.options.routes;
store.state.authList.forEach(auth => {
auth.children.forEach(item => {
var temp = pathRouterMapping[item.path];
currentRoutes[1].children.push(temp)
});
});
currentRoutes = currentRoutes.concat(notFoundRouter);
router.addRoutes(currentRoutes);
}
axios
其他
vue单页面应用中 新标签页中打开页面
单页面应用中,在新的标签页中打开当前的路由
1、标签方式:<router-link ></router-link>
<router-link target='_blank' tag='a'>去新标签页打开</router-link>
2、编程跳转方式:使用this.$router.resolve
let routerData = this.$router.resolve({
quert:'',
path:'/writeArticle'
});
window.open(routerData.href,'_blank')
vue谷歌调试工具
github上下载 默认是dev 选择一个 版本下载到本地
vscode打开下载好的文件
1、npm install 安装全部依赖
2、npm run build 打包
在shells下chrome即是打包好的插件包 在谷歌中导入即可
在vue中使用三方库的方式
将其作为全局对象挂载在window对象上
window._ = require('lodash');
component:
_.isEmpty?'':''
不可用于服务端渲染中 因为服务端没有window对象 为undefined
在每个需要该库的文件中引入
这种方式比较繁琐 并且当某一天不再依赖该库时候,必须一个个删除
将其放在vue的原型对象上去
1、
import lodash from 'lodash';
Vue.prototype.$lodash = lodash;
使用:
this.$lodash.xxx = xxxxxx;
2、
import lodash from 'lodash';
Object.defineProperty(Vue.prototype,'$lodash',{value:lodash})
这种方式挂载到vue原型对象上 可以利用Object.defineProperty中是否可写、
是否可在for循环中遍历等属性对其进行限制 防止做一些错误的操作
比如:this.$lodash = 'xxxxx'
写成插件形式
首先新建文件 MyLodash.js
在main.js中引入并使用use挂载
import MyLodash from 'MyLodash.js';
Vue.use(MyLodash);// Vue使用use时,即是在调用install方法
MyLodash.js: //需要在install方法中处理
import lodash from 'lodash';
export default{
install(Vue){ // 第一个参数为Vue构造函数
Object.defineProperty(Vue.prototype,'$lodash',{value : lodash});
}
}
也可将install方法中第二个参数设置为定义使用插件时候的名字
export default{
install(Vue,name='$lodash'){ // 第一个参数为Vue构造函数
// 第二个参数可以用作为自定义插件的名字
Object.defineProperty(Vue.prototype,name,{value : lodash});
}
}
一些配置
vue-cli3 别名配置
vue.config.js:
const path = require('path');
function resolve(dir) {
return path.join(__dirname, dir)
}
module.exports = {
chainWebpack: (config) => {
config.resolve.alias
.set('components', resolve('src/components'))
.set('assets', resolve('src/assets'));
}
}