笔者工作中用到的js框架便是当下十分火热的vue,这篇文章用于记录和总结笔者工作和学习过程中遇到的关于vue框架的问题。以便以后遇到相同的问题能够快速找到解决办法。😄😄
- Vue 自定义标签的 src 属性不能使用相对路径的问题
我们都知道,当使用自己定义的组件和原生img标签用相对路径引入src的话,其实是会有不同结果的,如下1
2
3
4
5
6<!-- 正常加载 -->
<v-img :src="require('../../assets/logo.png')" />
<!-- 无法加载 -->
<v-img src="../../assets/logo.png" />
<!-- 正常加载 -->
<img src="../../assets/logo.png" />
为什么组件必须用 require() 引入图片才能生效,那为什么 img 标签可以直接使用相对路径呢?这和 vue-loader 资源路径处理 有关系。
参考官方文档的资源路径处理我们可以知道:
默认情况下,vue-loader 使用 css-loader 和 Vue 模版编译器自动处理样式和模版文件。在编译过程中,所有的资源路径例如 、background: url(…) 和 @import 会作为模块依赖。
例如,url(./image.png) 会被转换为 require(‘./image.png’),而
1 | <img src="../image.png"> |
将会编译为:
1 | createElement('img', { attrs: { src: require('../image.png') }}) |
那么如何解决组件不用require也能引入相对路径的问题呢?
由于vue cli2升级到了vue cli3 但其实只是修改的配置项名称变了而已,
修复静态资源引用的问题 vue cli 2 => vue cli 3 升级之后配置项由 transformToRequire 改为 transformAssetUrls
(注:vue cli3是通过链式操作去修改webpack配置并覆盖之前的配置的,详细请看文档)
我们只需要在vue-loader的配置下面找到这两个字段
然后添加如下代码即可:
1 | transformToRequire(或者transformAssetUrls): { |
参考文章 https://segmentfault.com/a/1190000020399622
watch和compute的区别和联系
watch擅长处理的场景:一个数据影响多个数据1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21data() {
haiZeiTuan_Name: '草帽海贼团',
suoLong: '草帽海贼团索隆',
naMei: '草帽海贼团娜美',
xiangJiShi: '草帽海贼团香吉士'
},
/*
在watch中,一旦haiZeiTuan_Name(海贼团名称)发生改变
data选项中的船员名称全部会自动改变 (suoLong,naMei,xiangJiShi)
并把它们打印出来
*/
watch: {
haiZeiTuan_Name: function (newName) {
this.suoLong = newName + '索隆'
this.naMei = newName + '娜美'
this.xiangJiShi = newName + '香吉士'
console.log(this.suoLong)
console.log(this.naMei)
console.log(this.xiangJiShi)
}
}computed擅长处理的场景:一个数据受多个数据影响
1
2
3
4
5
6
7
8
9
10
11data() {
// 路飞的全名:蒙奇·D·路飞
firstName: '蒙奇',
secName: 'D',
thirdName: '路飞'
},
computed: {
luFei_Name: function () {
return this.firstName + this.secName + this.thirdName
}
}为什么vue组件中的data属性是一个函数,而不是一个对象
在 new Vue() 中,data 是可以作为一个对象进行操作的,然而在 component 中,data 只能以函数的形式存在,不能直接将对象赋值给它
1 | new Vue({ |
这并非是 Vue 自身如此设计,而是跟 JavaScript 特性相关,我们来回顾下 JavaScript 的原型链
1 | var Component = function() {}; |
以上两个实例都引用同一个对象,当其中一个实例属性改变时,另一个实例属性也随之改变,只有当两个实例拥有自己的作用域时,才不会互相干扰
data为函数类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。
1 | var Component = function() { |
- var vm = new Vue(), 但是为什么直接用this就可以访问到data里面的数据呢?

按常规理解来说,应该是vm.data.name这种形式才能访问到。参考文章
简单的说, vue 在初始话的过程中把 data 复制到了它的实例上,这样做的原因大概是方面用户使用。
在vue源码中,可以发现数据data是定义在初始化对象$options中的,要想访问到data中的key字段,正常来说是通过vm.$options.data.key来访问的。那么,在vue中是怎么实现利用vm.key就能访问到key字段呢。在源码中,有一个方法为initData()。
1 | function initData (vm) { |
在initData方法中,主要做的工作有:
将vm.$options.data映射到vm._data中,使得可以通过vm._data访问数据变量
处理data与props、methods之间的变量命名冲突的情况
通道代理方法proxy来实现vm直接访问data中的数据变量
1
2
3
4
5
6
7
8
9
10
11
12var sharedPropertyDefinition = {
enumerable: true,
configurable: true,
get: noop,
set: noop
};//设置通用数据属性变量。此变量就是对vm._data(也就是vm.$options.data)的代理
function proxy (target, sourceKey, key) {
sharedPropertyDefinition.get = function proxyGetter () {
return this[sourceKey][key]
};/对属性变量添加get方法。在读取此属性的时候,实际上读取的是vm._data,也就是此变量就是对vm._data(也就是vm.$options.data)的代理<br><br>sharedPropertyDefinition.set = function proxySetter (val) {<br><br><em id="__mceDel">this[sourceKey][key] = val; </em>
<em id="__mceDel"><em id="__mceDel"> }; //添加set方法<br> Object.defineProperty(target, key, sharedPropertyDefinition); //通过Object.defineProperty方法,将key直接挂在vm下,并且通过sharePropertyDefinition属性的get和set方式,将对<br> vm._data的读取读和写操作映射到了vm.key,到此,便实现了vm.key直接操作数据的代理。<br>}</em></em>由vue.$set方法引发的关于视图数据更新的问题
笔者最近在开发中遇到一个问题,有一个循环展示的div盒子,div盒子里面有一个小图标可以点击控制是否显示,我们通过向每一项里面添加一个变量来控制该小图标的显示隐藏。代码如下
1 | 数据格式为 |
上面为常规方法解决此问题。下面方法也可实现相同效果
1 | this.ajaxData.taskNewsVos[i].show = true; |
其实还有好几种办法,笔者还尝试过一种办法,代码如下:
1 | control: [] //新建数组来保存控制每一项控制显示的那个值 |
其实笔者还发现一个问题,可以做做笔记,大家感兴趣的可以留意一下
1 | this.hobby[0] = "reading" //单独执行此代码,视图并不会更新,这是合理的,因为vue的监听数据的机制如此 |