Vue单文件组件的开发以及CLI脚手架的使用
Vue.component全局注册组件的方式的缺点
Vue.component方式 定义的全局组件很方便,但是它有几个天生的缺陷,导致它只能用在很小的项目中,无法发挥Vue框架的全部实力。
- 它是全局自定义的,要求组件的名称全局唯一,组件数量一旦较多就很难管理。
- 它没有办法被编辑器的语法高亮支持,编写复杂的template时比较麻烦。
- 它不支持CSS,需要在外部定义组件的样式,影响组件的使用效率。
- 它不支持动态构建,无法使用预处理和热加载。
Vue的单文件组件解决方案及其环境安装和配置
Vue框架给出的解决方案时.vue后缀的单文件组件。
那么如何使用.vue为后缀的单文件组件来享受Vue提供给我们的这些便利呢?
- 首先,需要安装node.js框架,通过安装这个框架,我们可以获得一系列自动化的工具如npm,当然也可以自行安装yarn来作为npm的替代。但是node.js是一定要安装的。
- 安装完毕node.js之后,我们通过npm命令安装vue脚手架.-g是指将vue脚手架安装到全局用户。
npm install -g @vue/cli
- 安装完成之后,可以通过vue命令查看安装是否成功以及安装的vue版本
vue --version
如图
4. 接下来,我们就可以通过vue的create指令创建新的前端vue工程。并选择default模式。然后脚手架会自动安装工程需要的全部依赖
vue create vue-demo
-
创建完成后的vue-demo工程会存在于用户文件夹下的当前用户下。可以看到脚手架帮助我们创建了很多基础文件,甚至为我们创建了本地git。
如图:
-
在控制台中通过cd进入这个目录文件夹,然后通过npm或yarn命令启动项目。推荐使用yarn方式。
npm run serve
或者
yarn serve
7.此时已经可以访问创建的vue-demo了
现有组件的单文件化改造
为了进一步深入学习,接下来,我们要把前面一直在优化的todo-list和todo-item组件改造成Vue单文件组件,并使用前端框架的形式访问。
- 打开vue-demo前端项目的入口文件main.js,这个文件中定义了vue的根节点名称。
new Vue({
render: h => h(App),
}).$mount('#app')
起到的作用类似于
var vm = new Vue({
el: "#app",
/.../
})
- render:h=>h(App)代表入口组件是App.vue,我们需要在App.vue引入并注册todo-list和todo-item组件。
- App.vue默认引用并注册了一个叫HelloWorld的组件。从这个示例证明,要想在App.vue中引入我们自己的组件,我们先要为这两个组件创建自己的单文件.vue文件。
- 按照约定,我们在components文件夹在创建两个vue后缀文件。
- 首先是todo-item.vue。通过观察helloWorld.vue,我们可以发现,一个vue文件是由三大块组成的。
- template用来放置模板,相当于现有组件中的template标签。
- script用来放置组件的数据(data),方法(methods),属性(props)
- style是原有组件中不予支持的样式表
<template>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
- 按照这个结构,我们需要将原有todo-item组件下的template部分,放置到template标签中
template: `
<li>
<slot name="pretext" :val="vrandom"></slot>
<span v-if="!del">{{title}}</span>
<span v-else style="text-decoration:line-through">{{title}}</span>
<button v-show="!del" @click="handleClick">删除</button>
<slot name="suftext">默认尾部</slot>
</li>`,
变为
<template>
<li>
<slot name="pretext" :val="vrandom"></slot>
<span v-if="!del">{{title}}</span>
<span v-else style="text-decoration:line-through">{{title}}</span>
<button v-show="!del" @click="handleClick">删除</button>
<slot name="suftext">默认尾部</slot>
</li>
</template>
- 将原组件中的props,data,methods放置到script标签中。
<script>
export default {
props: {
title: String,
del: {
type: Boolean,
default: false
}
},
data: function() {
return {
vrandom:Math.random()
};
},
methods: {
handleClick(){
console.log("点击删除按钮!");
this.$emit('delete',this.title);
}
}
}
</script>
- 同理,我们创建todo-list.vue
<template>
<ul>
<slot></slot>
</ul>
</template>
<script>
export default {
data: function() {
return {
};
},
methods:{
}
}
</script>
<style scoped>
</style>
9.在App.vue将todo-item.vue和todo-list.vue引入并注册.
<script>
import todolist from './components/todo-list.vue'
import todoitem from './components/todo-item.vue'
export default {
name: 'App',
components: {
todolist,
todoitem
}
}
</script>
- 我们注册了todolist和todoitem,我们需要在App.vue中使用它。要使用这两个组件,我们需要准备相应的数据。将原new Vue中的data数据和methods方法移到App.vue中。
App.vue的完整script如下
<script>
import todolist from './components/todo-list.vue'
import todoitem from './components/todo-item.vue'
export default {
name: 'App',
components: {
todolist,
todoitem
},
data(){
return{
list: [
{
title: "新课程1",
del: false
},
{
title: "新课程2",
del: true
},
{
title: "新课程3",
del: false
}
]
};
},
methods: {
handleDelete(vtitle){
console.log("删除工程!",vtitle)
}
}
}
</script>
- 最后将原页面中html代码,即使用todo-list和todo-item组件的html移至App.vue中。
<template>
<div id="app">
<todolist>
<todoitem v-on:delete="handleDelete" v-for="item in list" data-wen="wen" :title="item.title" :del="item.del">
<template v-slot:pretext="{val}">
<label>前置文字{{val}}</label>
</template>
</todoitem>
</todolist>
</div>
</template>
此时有两个细节需要处理:
- v-for 后面需要动态绑定Key关键字。
- 使用的组件名要与注册的组件名一致。前期我们的组件一直叫todo-item,但是我们在本次注册时将组件注册为了todoitem,那么同理我们需要在使用时将名称对应起来。否则会报如下错误。
- 全部完成后,效果如图
至此,我们就完成了两个组件的单文件话改造。现在注册到App.vue的组件todolist和todoitem都是局部作用域,不会污染和与其他组件冲突。
那么,假如我们希望将todolist在全局注册怎么做能?
我们只需要在main.js中引入todolist并通过Vue.component注册即可。
import todolist from './components/todolist.vue'
Vue.component("todolist", todolist);
即
import Vue from 'vue'
import App from './App.vue'
import todolist from './components/todolist.vue'
Vue.component("todolist", todolist);
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
但是一般建议少注册全局组件。
单文件组件中的样式的使用
单文件组件中我们还有一个内容一直没有使用:style,我们可以通过style定义自己组件的样式,并且保证这个样式只会对自己起作用而不污染其他组件。
写法如下:
<style scoped>
.redsapn{color: red}
</style>
通过写在scoped标签,Vue框架会对我们的样式生成一个唯一哈希值,保证样式的唯一。
譬如,我们为todoitem组件增加上述样式,并在组件的template中使用:
<template>
<li>
<slot name="pretext" :val="vrandom"></slot>
<span class="redsapn" v-if="!del">{{title}}</span>
<span v-else style="text-decoration:line-through">{{title}}</span>
<button v-show="!del" @click="handleClick">删除</button>
<slot name="suftext">默认尾部</slot>
</li>
</template>
执行效果如下: