现在说到前端框架自然会想到的就是Angular、React、Vue 这三者。Angular虽然买了书,但是没有用过(书还是1.0的……)。React其实原本是在学RN时带上的,跟着慕课网上的教程做了个小练习 React 图片画廊 踩坑笔记。
Vue的话毕竟是国人做的框架,一直就想学习一下的。于是就打算把之前React的这个小项目用Vue来重写一遍当作入门练习了。
接触新框架难免要踩坑,其中有几次感觉自己要死在坑里了。不过最后靠着官方文档和谷歌的帮助还是爬了出来。而这篇便是在完成后对所踩过的坑的一个总结。
*当然,本着一篇文章太长会没人看的原则。先列一下踩坑的大致数量,可能会分两篇来写完。
项目地址:
项目效果:画廊效果 (React版)
- Vue-cli .js?.Vue?
- 父组件向子组件传值
- eslint format
- Vue中使用SCSS
- class绑定与顺序
- v-for 子组件DOM的取得
- 子组件向父组件的传递
- 数组的更新方法
Vue-cli .js?.Vue?
在Vue的官方网站的安装教程中,对于Vue-cli有这样的提示。
你可以查看安装教程来了解其他安装 Vue 的选项。请注意我们不推荐新手直接使用 vue-cli
,尤其是对 Node.js 构建工具不够了解的同学。
自然,作为一个玩过Node的人,当然是表示不服气的。想都不想的就作死的敲下了$ npm install --global vue-cli
。
待全部安装完成、创建项目之后。打开其中的Vue文件,就瞬间傻眼了。
因为在官网中给出的文档是这样的。
var app5 = new Vue({
el: '#app-5',
data: {
message: 'Hello Vue.js!'
},
methods: {
reverseMessage: function () {
this.message = this.message.split('').reverse().join('')
}
}
})
而生成好的Vue文件是这样的。
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h2>Essential Links</h2>
<ul>
<li><a href="https://vuejs.org" target="_blank">Core Docs</a></li>
<li><a href="https://forum.vuejs.org" target="_blank">Forum</a></li>
<li><a href="https://gitter.im/vuejs/vue" target="_blank">Gitter Chat</a></li>
<li><a href="https://twitter.com/vuejs" target="_blank">Twitter</a></li>
<br>
<li><a href="http://vuejs-templates.github.io/webpack/" target="_blank">Docs for This Template</a></li>
</ul>
<h2>Ecosystem</h2>
<ul>
<li><a href="http://router.vuejs.org/" target="_blank">vue-router</a></li>
<li><a href="http://vuex.vuejs.org/" target="_blank">vuex</a></li>
<li><a href="http://vue-loader.vuejs.org/" target="_blank">vue-loader</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank">awesome-vue</a></li>
</ul>
</div>
</template>
<script>
export default {
name: 'hello',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
怎么看这两个的差距都是有点大的。
但其实上一个是js文件中的写法,而后一个则是Vue的模板文件的写法。如果采用上一种写法的话,那应该还是和以前一样是HTML+CSS+JS分开管控,对于小项目这种可能会更好。(其实画廊应用应该更适合这一种)而且这一种也与React的写法相类似,从React转的话可能会更方便一些。
Vue的模板文件从后缀名就能看出.vue
,对于模板文件浏览器肯定是不认识的,因此Vue的模板文件一定需要经过编译才能使用。仔细看一下其实就能发现,Script的部分其实和上一种是一样的(除了写法上),从大体的结构可以看出,Vue的模板文件中分为了template、script、style三个部分,分别代表了HTML、JS、CSS三个部分,这样一来一个.vue文件就是一个组件。而一个App就是许多个组件组成起来的。这也正符合了组件化的思想。
关于前端以及组件化的一些感想
前端在HTML、CSS、JS上从最初HTML、CSS、JS文件的分离,到现在组件化在小组件内的耦合,感觉整个方向在越来越清晰了。HTML、CSS、JS文件分离是从功能角度上看的,每个文件各司其职。文件结构是很清晰了,但是实际在复用的时候往往不方便。如果只是一个部分的复用,那么从一堆HTML、CSS、JS中截取一小段还是很麻烦的。可能是这样的原因,才有了组件化的想法吧。组件化就是从另一个角度来看了,如同(宏观)物理学中定义原子是不可再分一样,在Web应用中,组件便是不可再分的了。原子中我们知道有中子、质子等,对应的一个组件中自然也有模板、样式和行为(JS)了。而以组件为单位的复用,既可以是最小的原子组件、也可以是由原子组件组成的分子组件。这么一来就提高了复用度,对于复用的场景也很灵活,想必组件化也会是今后的一个主流吧。
父组件向子组件传值
父组件向子组件传值,与React类似,通过props进行传值。不过所传的props的值必须要在子组件中事先定义好。在子组件中可以通过this.$props.value
来取得对应传进来的值。
<template>
<figure class="picture-continer"
:style="{top: imgPos.position.top + 'px', left: imgPos.position.left + 'px', transform:'rotate(' + this.imgPos.rotate + 'deg)'}"
:class="{'is-center':imgPos.isCenter,'is-inverse':imgPos.isInverse}"
@click.stop="pictureAction">
<img :src="picture.src"
:alt="picture.title" />
<h2 class="img-title">{{picture.title}}</h2>
<div class="img-back">
<p>{{picture.desc}}</p>
</div>
</figure>
</template>
<script>
// 引入event bus 作为组件间事件传递的中间件
import bus from '../assets/eventBus.js';
export default {
name: 'picture',
props: ['picture', 'img-pos', 'index'], // 在这里使用中划线命名,但在上面template中采用驼峰式
methods: {
pictureAction: function () {
if (this.$props.imgPos.isCenter) {
// this.$props.imgPos.isInverse = !this.$props.imgPos.isInverse;
bus.$emit('refresh-pic', this.$props.index);
} else {
bus.$emit('do-rearrange', this.$props.index);
}
}
},
data() {
return {
// imgPos: this.$props
}
},
mounted() {
},
updated() {
this.$nextTick(function () {
if (this.$props.imgPos.isCenter) {
// 由于roate 是内联样式,对于center的图片需要消除后才能让class的样式起作用
this.$el.style.transform = '';
}
});
}
}
</script>
<style lang="scss">
.picture-continer {
width: 320px;
height: 360px;
margin: auto;
padding: 40px 40px 0px 40px;
box-sizing: border-box;
border-radius: 1px;
background-color: #fff;
position: absolute;
cursor: pointer;
transform-style: preserve-3d;
transform-origin: 0 50% 0; // 改变变化的原点为x轴原点
transition: left .8s ease-in-out, top .8s ease-in-out, transform .5s;
perspective: 1800px;
h2 {
height: 80px;
margin: 0;
line-height: 80px;
color: #727272;
text-align: center;
font-size: 16px;
}
}
.img-back {
width: 320px;
height: 360px;
overflow: auto;
position: absolute;
left: 0;
top: 0;
background-color: #fff;
transform: rotateY(-180deg);
p {
padding: 40px;
color: #727272;
font-size: 16px;
}
}
.is-center {
transform: rotate(0deg);
z-index: 11;
}
.is-inverse {
transform: translate(320px) rotateY(180deg);
}
</style>
eslint format
由于Vue-cli中是会开启eslint来检查javascript的语法的。但是,对于添加分号、方法名与括号之间必须有空格这种规定还是很讨厌的。然而如果不通过eslint的话,网页又是无法显示的。
所以可以通过在.eslintrc.js
中添加一些规则把eslint中的一些检测给关了。
具体如何修改可以参考官方网站(是有中文版的哦~)
// http://eslint.org/docs/user-guide/configuring
module.exports = {
root: true,
parser: 'babel-eslint',
parserOptions: {
sourceType: 'module'
},
env: {
browser: true,
},
// https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
extends: 'standard',
// required to lint *.vue files
plugins: [
'html'
],
// add your custom rules here
'rules': {
// 在rules中可以添加对应的规则,0是关闭、1或者其他的数值是开启
// allow paren-less arrow functions
'arrow-parens': 0,
// allow async-await
'generator-star-spacing': 0,
// allow debugger during development
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
// 函数名后不需要空格
'space-before-function-paren': 0,
// 禁止不需要的分号
'no-extra-semi': 0,
// 永远需要分号
'semi': 0,
'no-new':0,
'eol-last':0
}
}
感觉篇幅已经很长了,所以第一篇就先到此打住。剩下的5个就在下一篇中记录吧。