vue(五)
1.动态组件
- 组件的显示与隐藏切换
1.1 <component>
组件
- 组件的一个占位符
- 通过设置属性来显示不同的组件
- is属性来指定要显示哪个属性
示例
<template>
<div class="app-container">
<h1>App 根组件</h1>
<hr />
<div class="box">
<!-- 渲染 Left 组件和 Right 组件 -->
<!-- 使用内置的component组件 -->
<!-- 占位符,按需渲染不同的组件 -->
<component is="Left"></component>
<!-- <Left></Left> -->
</div>
</div>
</template>
<script>
// 导入left组件
import Left from "@/components/Left.vue"
export default {
components:{
Left
}
}
</script>
<style lang="less">
.app-container {
padding: 1px 20px 20px;
background-color: #efefef;
}
.box {
display: flex;
}
</style>
- 效果图
示例:组件按需切换
<template>
<div class="app-container">
<h1>App 根组件</h1>
<hr />
<!-- 实现按需切换组件 -->
<button @click="comName='left'">展示left组件</button>
<button @click="comName='Right'">展示Right组件</button>
<div class="box">
<!-- 渲染 Left 组件和 Right 组件 -->
<!-- 使用内置的component组件 -->
<!-- 占位符,按需渲染不同的组件 -->
<component :is="comName"></component>
<!-- <Left></Left> -->
</div>
</div>
</template>
<script>
// 导入left组件
import Left from "@/components/Left.vue"
// 导入Right组件
import Right from "@/components/Right.vue"
export default {
// 使用data存储要展示的组件名称
data(){
return {
comName:'left'
}
},
components:{
Left,
Right
}
}
</script>
<style lang="less">
.app-container {
padding: 1px 20px 20px;
background-color: #efefef;
}
.box {
display: flex;
}
</style>
- 效果图
1.2 组件被切换时
-
默认会被销毁和创建
-
left组件
<template>
<div class="left-container">
<h3>Left 组件----------{{count}}</h3>
<button @click="count+=1">+1</button>
</div>
</template>
<script>
export default {
data(){
return {
count:0
}
},
created(){
console.log('left组件被创建');
},
destroyed(){
console.log('left组件被销毁');
}
}
</script>
<style lang="less">
.left-container {
padding: 0 20px 20px;
background-color: orange;
min-height: 250px;
flex: 1;
}
</style>
- app根组件
<template>
<div class="app-container">
<h1>App 根组件</h1>
<hr />
<!-- 实现按需切换组件 -->
<button @click="comName='left'">展示left组件</button>
<button @click="comName='Right'">展示Right组件</button>
<div class="box">
<!-- 渲染 Left 组件和 Right 组件 -->
<!-- 使用内置的component组件 -->
<!-- 占位符,按需渲染不同的组件 -->
<component :is="comName"></component>
<!-- <Left></Left> -->
</div>
</div>
</template>
<script>
// 导入left组件
import Left from "@/components/Left.vue"
// 导入Right组件
import Right from "@/components/Right.vue"
export default {
// 使用data存储要展示的组件名称
data(){
return {
comName:'left'
}
},
components:{
Left,
Right
}
}
</script>
<style lang="less">
.app-container {
padding: 1px 20px 20px;
background-color: #efefef;
}
.box {
display: flex;
}
</style>
- 效果图
1.3 keep-alive 保持状态
-
一个内置的标签(
) -
在其文本区域放置要保持状态的组件
-
结果
- 组件在切换时,不在被销毁,而是被缓存,不在被创建,而是被激活
1.3.2 keep-alive状态下的生命周期
- 组件被缓存时,触发deactivated生命周期函数
- 组件被激活时,触发activated生命周期函数
示例
- left组件
<template>
<div class="left-container">
<h3>Left 组件----------{{count}}</h3>
<button @click="count+=1">+1</button>
</div>
</template>
<script>
export default {
data(){
return {
count:0
}
},
created(){
console.log('left组件被创建');
},
destroyed(){
console.log('left组件被销毁');
},
// 在keep-alive状态下的生命周期
deactivated(){
console.log('left组件被缓存');
},
activated () {
console.log('left组件被激活');
}
}
</script>
<style lang="less">
.left-container {
padding: 0 20px 20px;
background-color: orange;
min-height: 250px;
flex: 1;
}
</style>
- app根组件
<template>
<div class="app-container">
<h1>App 根组件</h1>
<hr />
<!-- 实现按需切换组件 -->
<button @click="comName='left'">展示left组件</button>
<button @click="comName='Right'">展示Right组件</button>
<div class="box">
<!-- 渲染 Left 组件和 Right 组件 -->
<!-- 使用内置的component组件 -->
<!-- 占位符,按需渲染不同的组件 -->
<!-- keep-alive标签保持组件的状态 -->
<keep-alive>
<component :is="comName"></component>
</keep-alive>
<!-- <Left></Left> -->
</div>
</div>
</template>
<script>
// 导入left组件
import Left from "@/components/Left.vue"
// 导入Right组件
import Right from "@/components/Right.vue"
export default {
// 使用data存储要展示的组件名称
data(){
return {
comName:'left'
}
},
components:{
Left,
Right
}
}
</script>
<style lang="less">
.app-container {
padding: 1px 20px 20px;
background-color: #efefef;
}
.box {
display: flex;
}
</style>
- 效果图
1.4 keep-alive的include和exclude属性
- include属性:决定哪些组件被缓存
- exclude属性:决定哪些组件不被缓存
- include和exclude不可同时使用
- keep-alive默认缓存所有的组件
示例
- 只缓存Left组件
<keep-alive include="Left">
<component :is="comName"></component>
</keep-alive>
1.5 声明组件时为组件起名称
- export default 中的name属性
- Right组件起名称
<template>
<div class="right-container">
<h3>Right 组件</h3>
</div>
</template>
<script>
export default {
// 为组件起自己的名称
name:'MyRight'
}
</script>
<style lang="less">
.right-container {
padding: 0 20px 20px;
background-color: lightskyblue;
min-height: 250px;
flex: 1;
}
</style>
- 效果图
注意点
- 注册名称用于标签使用组件
- 声明的名称不管调试,还是keep-alive的exlude,include属性都用这个
2. 插槽
- 定义
插槽(Slot):vue组件中的占位符:把不确定的,希望由用户指定的部分
- 图解
2.1 插槽的使用
-
<slot></slot>
插槽占位符的使用 -
left组件使用插槽占位符
<template>
<div class="left-container">
<h3>Left 组件</h3>
<!-- 定义插槽占位符 -->
<slot></slot>
</div>
</template>
<script>
export default {}
</script>
<style lang="less">
.left-container {
padding: 0 20px 20px;
background-color: orange;
min-height: 250px;
flex: 1;
}
</style>
- app使用left组件,在插槽位置自定义内容
<template>
<div class="app-container">
<h1>App 根组件</h1>
<hr />
<div class="box">
<!-- 渲染 Left 组件和 Right 组件 -->
<!-- Left插槽 -->
<Left>
<!-- 插槽位置自定义内容 -->
<p>用户自定义</p>
</Left>
</div>
</div>
</template>
<script>
// 导入Left组件
import Left from '@/components/Left.vue'
export default {
components:{
Left,
}
}
</script>
<style lang="less">
.app-container {
padding: 1px 20px 20px;
background-color: #efefef;
}
.box {
display: flex;
}
</style>
- 效果图
2.2 具名插槽
-
vue官方规定,每个
插槽都有一个name属性,如果不指定,默认name的值为default -
默认情况下,使用组件时,组件的内容部分默认渲染到name属性值为default的插槽处
2.3 将内容渲染到指定插槽
示例:填充到default插槽
- app要填充的内容
<Left>
<!-- 插槽位置自定义内容 -->
<!-- 将内容填充到指定的插槽,使用v-slot指令 -->
<template v-slot:default>
<p>用户自定义</p>
</template>
</Left>
- left组件的插槽部分
<template>
<div class="left-container">
<h3>Left 组件</h3>
<!-- 定义插槽占位符 -->
<slot name="default"></slot>
</div>
</template>
注意点
-
v-slot指令需要添加到
<template>
标签上 -
标签为虚标签,不含事件意义
2.4 v-slot指令的简写形式
- 一个#号
2.5 在
<slot>
标签内容部分可以放置默认内容- 存在要填充内容,插槽部分为填充内容
- 无填充内容,显示插槽的默认内容
示例
- left组件
<slot name="default">默认内容</slot>
- app组件
<Left> <!-- 插槽位置自定义内容 --> <!-- 将内容填充到指定的插槽,使用v-slot指令 --> <!-- <template v-slot:default> <p>用户自定义</p> </template> --> </Left>
- 效果图
使用v-slot插槽的练习
- Article组件
<template> <div class="Article-container"> <!-- 文章标题 --> <div class="article_title"> <slot name="title"></slot> </div> <!-- 文章内容 --> <div class="article_content"> <slot name="content"></slot> </div> <!-- 文章作者 --> <div class="article_author"> <slot name="author"></slot> </div> </div> </template> <script> export default { name:"Article" } </script> <style lang="less" scoped> .Article-container{ >div{ min-height: 150px; } .article_title{ background-color: blue; } .article_content{ background-color: green; } .article_author{ background-color: red; } } </style>
- app组件
<template> <div class="app-container"> <h1>App 根组件</h1> <hr /> <Article> <template #title> <div> <p>my poem</p> </div> </template> <template #author> <div> <p>author</p> </div> </template> <template #content> <div> <p>my content</p> </div> </template> </Article> <div class="box"> <!-- 渲染 Left 组件和 Right 组件 --> <!-- Left插槽 --> <Left> <!-- 插槽位置自定义内容 --> <!-- 将内容填充到指定的插槽,使用v-slot指令 --> <!-- <template v-slot:default> <p>用户自定义</p> </template> --> </Left> <!-- 使用Article组件 --> </div> </div> </template> <script> // 导入Left组件 import Left from '@/components/Left.vue' // 导入Article组件 import Article from '@/components/Article.vue' export default { components:{ Left, Article } } </script> <style lang="less"> .app-container { padding: 1px 20px 20px; background-color: #efefef; } .box { display: none; } </style>
- 效果图
2.6 作用域插槽
-
给插槽绑定属性,可以让插槽的使用者(父)获取到绑定的属性值
-
Article作用域插槽
<div class="article_content"> <!-- 作用域插槽绑定属性 --> <slot name="content" msg="hello vue.js" :user="userinfo"></slot> </div>
- app
<template #content="scope"> <div> <p>my content</p> <!-- 作用域插槽的内容获取 --> <p>{{scope}}</p> </div> </template>
- 效果图
- app也可解构赋值
<template #content="{msg,user}"> <div> <p>my content</p> <!-- 作用域插槽的内容获取 --> <p>{{msg}}</p> <p>{{user}}</p> </div> </template>
- 效果图
3. 自定义指令
3.1 私有自定义指令
-
在组件export default 的 directives 节点下声明私有自定义指令
-
注意点
- 在声明时不需要添加v-
- 使用时加上v-
示例
<template> <div class="app-container"> <!-- 使用自定义指令 --> <h1 v-color>App 根组件</h1> <hr /> <div class="box"> <!-- 渲染 Left 组件和 Right 组件 --> </div> </div> </template> <script> export default { // 声明自定义指令 directives: { color:{ bind (el) { el.style.color='red' }, } } } </script> <style lang="less"> .app-container { padding: 1px 20px 20px; background-color: #efefef; } .box { display: flex; } </style>
- 效果图
3.2 使自定义指令的值用户自定义
<template> <div class="app-container"> <!-- 使用自定义指令 --> <!-- 传递变量值 --> <h1 v-color="color">App 根组件</h1> <!-- 传递一个固定的值 --> <p v-color="'pink'">我是一个p标签</p> <hr /> <div class="box"> <!-- 渲染 Left 组件和 Right 组件 --> </div> </div> </template> <script> export default { data(){ return { // 将该属性绑定给v-color color:'red' } }, // 声明自定义指令 directives: { color:{ // 第一个参数,绑定的元素,第二个参数,传递过来的值 bind (el,binding) { console.log(binding); el.style.color=binding.value; }, } } } </script> <style lang="less"> .app-container { padding: 1px 20px 20px; background-color: #efefef; } .box { display: flex; } </style>
- 效果图
3.3 update函数
- bind函数只调用一次(DOM元素被绑定的时候),当DOM更新后不在触发
- update函数在DOM更新的时候被触发
3.4 全局自定义指令
-
全局性质的指令,过滤器,。。。都定义到main.js文件中
-
main.js
import Vue from 'vue' import App from './App.vue' // 定义一个全局自定义指令 Vue.directive('color', function(el, binding) { el.style.color = binding.value; }) // 或者 // Vue.directive('color', { // bind(el, binding) { // el.style.color = binding.value; // }, // update(el, binding) { // el.style.color = binding.value; // } // }) Vue.config.productionTip = false new Vue({ render: h => h(App), }).$mount('#app')
4. eslint的使用
- 创建vue 项目时勾选eslint
- 选择 eslint standrad
4.1 插件安装
- 格式化代码,使其符合eslint的规则
4.2 设置函数前面无空格的规则
- .eslintrc.js中配置
module.exports = { root: true, env: { node: true }, extends: ['plugin:vue/essential', '@vue/standard'], parserOptions: { parser: '@babel/eslint-parser' }, rules: { // 禁用console 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', // 禁用debugger,在页面中写一句debugger,可以使页面停止到这里,页面一直刷新 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', // 无空格规则 'space-before-function-paren': ['warn', 'never'] } }
4.3 插件安装与配置
4.4 插件配置
- setting.json中配置
{ "editor.fontSize": 16, "editor.unicodeHighlight.allowedCharacters": { ":": true }, "files.autoSave": "onFocusChange", "less.compile": { "out": "../css/" }, "editor.unicodeHighlight.allowedLocales": { "zh-hans": true }, "workbench.colorTheme": "Monokai Dimmed", "open-in-browser.default": "C:\\Users\\86183\\AppData\\Local\\Google\\Chrome\\Application\\chrome.exe", "cssrem.rootFontSize": 80, "previewServer.browsers": [], "previewServer.startupProject": "", "previewServer.port": 80, "git.enabled": false, // 导入文件是否携带扩展名 "path-autocomplete.extensionOnImport": true, // 配置@的路径提示 "path-autocomplete.pathMappings": { "@": "${folder}/src" }, "editor.tabSize": 2, "editor.formatOnSave": true, // ESLint 插件的配置 "editor.codeActionsOnSave": { "source.fixAll": true, }, "prettier.configPath": "C:\\Users\\86183\\.prettierrc", "eslint.alwaysShowStatus": true, "prettier.trailingComma": "none", "prettier.semi": false, // 每行文字个数超出此限制将会被迫换行 "prettier.printWidth": 300, // 使用单引号替换双引号 "prettier.singleQuote": true, "prettier.arrowParens": "avoid", // 设置 .vue 文件中,HTML代码的格式化插件 "vetur.format.defaultFormatter.html": "js-beautify-html", "vetur.ignoreProjectWarning": true, "vetur.format.defaultFormatterOptions": { "js-beautify-html": { "wrap_attributes": false }, "prettier": { "printWidth": 300, "trailingComma": "none", "semi": false, "singleQuote": true, "arrowParens": "avoid" } }, // "[javascript]": { // "editor.defaultFormatter": "esbenp.prettier-vscode" // }, // "[vue]": { // "editor.defaultFormatter": "octref.vetur" // }, }
- 注意点
这是我的配置
"prettier.configPath": "C:\Users\86183\.prettierrc", 这行需要修改
- 这里面的文件内容
{ "semi": false, //使用分号,默认是true,改成false "singleQuote": true //使用单引号 }
5. 挂载全局的ajax
- main.js
import Vue from 'vue' import App from './App.vue' // 将axios挂载到vue示例的原型函数中,实现axios全局可用 import axios from 'axios' // 设置请求的根路径 axios.defaults.baseURL = 'http://www.liulongbin.top:3006' Vue.prototype.$http = axios Vue.config.productionTip = false new Vue({ render: (h) => h(App) }).$mount('#app')
- 某个组件使用
<template> <div class="right-container"> <h3>Right组件</h3> <!-- 发起get请求 --> <button @click="getinfo"></button> </div> </template> <script> export default { name: 'Right-c', methods: { async getinfo() { // 通过原型函数发起ajax请求 // console.log(111) const { data: res } = await this.$http.get('/api/get') console.log(res) } } } </script> <style lang="less" scoped> .right-container{ background-color: skyblue; min-height: 100px; flex: 1; } </style>
- 优点
每个组件调用ajax请求时,不需要导包了,根地址也可以简写,发请求方便
- 缺点
每个组件发起发起ajax请求时,都需要写一个函数,而函数内容大体一致,不利于api接口的复用