Vue
2021-10-30 12:54:38 5 举报
AI智能生成
Vue知识脉络,请收藏,持续更新
作者其他创作
大纲/内容
参考资料
Vue3官方文档
Vue2官方文档
Vue3 教程
Vue3 One Piece
相关导图
JavaScript
HTML
CSS
01 HTML开发
- 模板语法
- 模板语法
入门与常用特性
渐进式JavaScript框架
声明式渲染 -> 组件系统 -> 客户端路由 -> 集中式状态管理 -> 项目构建
引入
参考资料
Vue2 官方导入
Vue 3 官方安装
<script>引入js文件
大型项目使用其他安装开发方式
查看vue版本
参考资料
如何查看vue版本号
vue -V
脚手架版本
package.json
基本使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="app">
<div>{{msg}}</div>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data: {
msg: 'Hello Vue'
}
});
</script>
</body>
</html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="app">
<div>{{msg}}</div>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data: {
msg: 'Hello Vue'
}
});
</script>
</body>
</html>
常用特性
表单操作(基于Vue)
数据绑定
使用v-model进行表单绑定
事件绑定
使用@click.prevent="handle"进行提交
表单修饰符
number
v-model.number="age"
代替了parseInt()
trim
去掉开头和结尾的空格
lazy
将input事件(文字改变就触发)转化为change事件(失去焦点触发)
自定义指令
计算属性
过滤器
监听器
HTML骨架绑定 - 数据
参考资料
Vue基础之数据绑定
v-cloak
参考资料
v-cloak的作用
解决插值表达式闪动问题
代码加载的时候先加载HTML,把插值语法当做HTML内容加载到页面上,
当加载完js文件后才把插值语法替换掉,所以我们会看到闪烁问题。
当加载完js文件后才把插值语法替换掉,所以我们会看到闪烁问题。
展示文字 - 单向数据绑定
v-text
嵌入文本
简写成{{ }}
v-html
嵌入标签
v-pre
不编译
数据响应式
插值表达式绑定的数据内容自动具有响应式特点
v-once
初始响应一次,不要监听,提高性能
交互表单 -
双向数据绑定
双向数据绑定
v-model
<div>{{msg}}</div>
<div>
<input type="text" v-model='msg'>
</div>
<div>
<input type="text" v-model='msg'>
</div>
实现原理
<input v-bind:value='msg' v-on:input='msg=$event.target.value' />
父子组件双向数据绑定
HTML骨架绑定 - 属性 - :
参考资料
vue组件中冒号的作用
v-bind:
简写是冒号:
<a v-bind:href='url'></a>
JS动态绑定 - 事件 - @
参考资料
vue中'. native'修饰符的使用
Vue官方修饰符讲解
span 的click事件没有响应
在span的click上使用stop
vue.js @click绑定点击事件不生效?
Vue2 官方文档 v-on
在vue中使用鼠标事件@mousedown、@mouseenter等失效的解决办法,以及PC端长按实现
‘.native‘ modifier on ‘v-on‘ directive is deprecated
v-on: 或者 @
v-on:标准事件属性=‘js处理逻辑’
函数/方法定义在Vue实例对象里面
只传递函数名不加括号默认传递事件参数作为第一个参数
如果绑定函数调用,必须将事件参数作为最后一个参数显示传递,$event
(不作为最后一个也没什么关系?)
(不作为最后一个也没什么关系?)
鼠标事件修饰符
.stop
阻止冒泡
点击子事件会冒泡到父元素点击事件
.prevent
阻止默认行为
串联顺序重要
.native
@mouseenter、@mousedown等鼠标事件[非鼠标点击事件]时,发现事件不触发,失效了
此时应该在@mouseenter、@mouseenter等鼠标事件加上native属性就好了
此时应该在@mouseenter、@mouseenter等鼠标事件加上native属性就好了
vue3 native deprecated了
直接支持了
按键事件修饰符
.enter
<input v-on:keyup.enter='submit'>
.delete
<input v-on:keyup.delete='handle'>
传递参数的同时
传递事件对象
传递事件对象
参考资料
Vue:带参数函数在传递参数的同时传递事件对象
CSS外观绑定 - 样式 - :
class样式处理
对象语法
<div v-bind:class="{active: isActive,error: isError}">测试样式</div>
<button v-on:click='handle'>切换</button>
<body>
<div id="app">
<div v-bind:class="{active: isActive,error: isError}">测试样式</div><div id="app">
<button v-on:click='handle'>切换</button>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data: {
isActive: true,
isError: true
},
methods: {
handle: function(){
this.isActive = !this.isActive;
this.isError = !this.isError;
}
}
});
</script>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data: {
isActive: true,
isError: true
},
methods: {
handle: function(){
this.isActive = !this.isActive;
this.isError = !this.isError;
}
}
});
</script>
</body>
数组语法
<div v-bind:class='[activeClass, errorClass]'>测试样式</div>
<body>
<div id="app">
<div v-bind:class="{active: isActive,error: isError}">测试样式</div>
<button v-on:click='handle'>切换</button>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data: {
isActive: true,
isError: true
},
methods: {
handle: function(){
this.isActive = !this.isActive;
this.isError = !this.isError;
}
}
});
</script>
</body>
<div id="app">
<div v-bind:class="{active: isActive,error: isError}">测试样式</div>
<button v-on:click='handle'>切换</button>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data: {
isActive: true,
isError: true
},
methods: {
handle: function(){
this.isActive = !this.isActive;
this.isError = !this.isError;
}
}
});
</script>
</body>
style样式处理
<body>
<div id="app">
<div v-bind:style='{border: borderStyle, width: widthStyle, height: heightStyle}'></div>
<div v-bind:style='objStyles'></div>
<div v-bind:style='[objStyles, overrideStyles]'></div>
<button v-on:click='handle'>切换</button>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data: {
borderStyle: '1px solid blue',
widthStyle: '100px',
heightStyle: '200px',
objStyles: {
border: '1px solid green',
width: '200px',
height: '100px'
},
overrideStyles: {
border: '5px solid orange',
backgroundColor: 'blue'
}
},
methods: {
handle: function(){
this.heightStyle = '100px';
this.objStyles.width = '100px';
}
}
});
</script>
</body>
<div id="app">
<div v-bind:style='{border: borderStyle, width: widthStyle, height: heightStyle}'></div>
<div v-bind:style='objStyles'></div>
<div v-bind:style='[objStyles, overrideStyles]'></div>
<button v-on:click='handle'>切换</button>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data: {
borderStyle: '1px solid blue',
widthStyle: '100px',
heightStyle: '200px',
objStyles: {
border: '1px solid green',
width: '200px',
height: '100px'
},
overrideStyles: {
border: '5px solid orange',
backgroundColor: 'blue'
}
},
methods: {
handle: function(){
this.heightStyle = '100px';
this.objStyles.width = '100px';
}
}
});
</script>
</body>
注意点
数组与对象结合
[activeClass, errorClass, {test: isTest}]
简化绑定操作
<body>
<div id="app">
<div v-bind:class='arrClasses'></div>
<div v-bind:class='objClasses'></div>
<button v-on:click='handle'>切换</button>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data: {
arrClasses: ['active','error'],
objClasses: {
active: true,
error: true
}
},
methods: {
handle: function(){
this.objClasses.error = false;
}
}
});
</script>
</body>
<div id="app">
<div v-bind:class='arrClasses'></div>
<div v-bind:class='objClasses'></div>
<button v-on:click='handle'>切换</button>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data: {
arrClasses: ['active','error'],
objClasses: {
active: true,
error: true
}
},
methods: {
handle: function(){
this.objClasses.error = false;
}
}
});
</script>
</body>
默认的class处理
<div class="base" v-bind:class='objClasses'></div>
分支结构 v-if
参考资料
v-if 和 v-show 的区别,哪个性能更好?
Vue 学习之 v-if,v-for,v-on 以及生命周期
v-if 和 v-show在切换时vue生命周期钩子的执行
v-if
直接控制标签是否渲染到页面
开销大
适用场景
不停的创建和销毁,性能差一点
初始渲染开销小,但是切换开销大
生命周期
初始值为 false 组件不会渲染,生命周期钩子不会执行,v-if 的渲染是惰性的。
初始值为 true 时,组件会进行渲染,并依次执行 beforeCreate,created,beforeMount,mounted 钩子。
v-else
v-else-if
v-show
参考资料
Vue.js 中的 v-show 指令及用法详解
使用
v-show="type==='科技'"
控制style="display: none;"
开销小
适用场景
适用于频繁切换某节点时,切换性能消耗小,但是初始性能消耗大
生命周期
无论初始状态,组件都会渲染,依次执行
beforeCreate,created,beforeMount,mounted 钩子,v-show 的渲染是非惰性的。
beforeCreate,created,beforeMount,mounted 钩子,v-show 的渲染是非惰性的。
v-if和v-show并存
参考资料
vue中v-if与v-show同时使用
v-show=“demo” v-if="test"
demo和test定义时都是false,启动组件时同时改写成ture,
然后关闭组件时再更改v-show的显隐,之后就都控制v-show的显隐就成了。
然后关闭组件时再更改v-show的显隐,之后就都控制v-show的显隐就成了。
循环结构 v-for
参考资料
Vue3 官方文档 v-for
常见错误
v-for前面加了冒号
不能加
正确顺序是(item, index),不是Index在前面
如果传参给子组件,注意参数命名,要用kebab命名法或者驼峰命名法
有v-for就必定要有key
示例代码一
<DirectoryHolder :key='item' v-for='item in items.fileTree.directoryGroups' :directory-group="item" >
</DirectoryHolder>
</DirectoryHolder>
示例代码二
过滤与排序
参考资料
vue学习笔记3 v-for加排序
v-for列表过滤和排序
Vue3官方文档 - Displaying Filtered/Sorted Results
computed
直接在HTML中
使用Vue组件
使用Vue组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="app">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
Vue.component('button-counter', {
data: function(){
return {
count: 0
}
},
template: '<button @click="handle">点击了{{count}}次</button>',
methods: {
handle: function(){
this.count += 2;
}
}
})
var vm = new Vue({
el: '#app',
data: {
}
});
</script>
</body>
</html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="app">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
Vue.component('button-counter', {
data: function(){
return {
count: 0
}
},
template: '<button @click="handle">点击了{{count}}次</button>',
methods: {
handle: function(){
this.count += 2;
}
}
})
var vm = new Vue({
el: '#app',
data: {
}
});
</script>
</body>
</html>
组件化开发步骤
关键原则
用一个库安装一个
Phase 01
单组件化开发阶段
使用UI组件框架搭建单个组件
Phase 02
多组件拼接阶段
UI组件框架+Vue-router进行界面搭建与跳转管理
Phase 03
数据搭建阶段
调整Vue数据绑定,默认值与组件间参数传递
Phase 04
数据管理阶段
Vuex与Axios完成状态管理
02 Vue组件化开发
- 项目启动设置
- 项目启动设置
参考资料
尚硅谷前端体系Vue教程
Webstorm官方Vue启动
上手创建
前期准备
node和vue-cli更新到最新版本,
命令见右边对应导图节点
命令见右边对应导图节点
创建新项目
导入Vue-router
见右边导图节点,进入链接
导入其他各种包
项目结构
总览
Vue3 -
main.js
main.js
参考资料
vue3 main.js
Vue3+cli4.5.x 中使用“vue-axios“
基本格式
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.mount('#app')
import App from './App.vue'
const app = createApp(App)
app.mount('#app')
注册新的package
app.use(package_name)
项目启动
yarn serve
项目打包
npm
npm run build
yarn
yarn build
Idea自动部署
参考资料
webStorm 自动部署到远程服务器
配置服务器 Settings -> Build,Execution,Deployment->Deployment
配置Mappings
如果你不想上传或下载某些路径的文件,可以在excluded path上配置
高级配置 选中Always,一旦本地文件更新就会自动上传
Deployment -> Options
部署选中文件,右键可以选择你需要的操作
vue组件基本结构
<template>
</template>
<script>
export default {
name: "Hello"
}
</script>
<style scoped>
</style>
</template>
<script>
export default {
name: "Hello"
}
</script>
<style scoped>
</style>
命名规范
参考资料
views 命名规范
03-01 组件基础 -
基本概念
基本概念
组件命名
短横线
my-component
推荐
驼峰式
MyComponent
可能出现问题
只能在字符串模板中使用
生命周期
参考资料
Vue - 生命周期详解
Vue2官方文档
【Vue】 生命周期, created,mounted, methods , computed , watched, 通俗易懂
生命周期不断循环
参考资料
为什么vue的beforeUpdate和updated生命周期会不停的发送请求
03-02 组件基础 -
JS模块
JS模块
箭头函数
参考资料
vue data不可以使用箭头函数的问题解析
关于 ES6 箭头函数 用法 以及 Vue 中 data / method 里不能用箭头函数的坑点记录
使用箭头函数无法操作vue实例数据
请老老实实用function
数据 data
参考资料
Vue中data定义的三种方式和区别
vue定义data的三种方式与区别
注意
复用组件就不能够用对象了,
data必须是函数,
因为函数里面是函数局部作用域,形成闭包,
保证了组件可以重用,数据不会串
data必须是函数,
因为函数里面是函数局部作用域,形成闭包,
保证了组件可以重用,数据不会串
使用箭头函数无法操作vue实例数据
基本介绍
子组件自身的数据
对象写法
data: {
yanggb: 'yanggb'
}
yanggb: 'yanggb'
}
函数写法
data: function() {
return {
yanggb: 'yanggb'
}
}
return {
yanggb: 'yanggb'
}
}
ES6函数写法
data() {
return {
yanggb: 'yanggb'
}
}
return {
yanggb: 'yanggb'
}
}
属性 props
基本介绍
父组件向子组件传递的数据
所有需要传递的参数默认值都写在props里面
实例
props:{
type: {
default: "1"
},
title: {
default: "吉他入门"
}
},
type: {
default: "1"
},
title: {
default: "吉他入门"
}
},
方法 methods
参考资料
Vue中的methods方法
实例
methods:{
show: function(){
console.log("显示内容")
}
}
show: function(){
console.log("显示内容")
}
}
组件注册
components
components
参考资料
Vue2 官方文档 组件注册
组件内部注册
components: {
ComponentA,
ComponentC
},
ComponentA,
ComponentC
},
Html内注册
Vue.component('name',{
data:function(){},
template:'',
methods:{method1:function(){}}
})
监听值变化 watch
监听Vuex的Store值变化
参考资料
vue监听vuex的store值的变化
computed: {
getStoreItem () {
return this.$store.state.test
}
},
watch: {
getStoreItem () {
console.log(this.$store.state.test,'asfas fas fas')
}
},
getStoreItem () {
return this.$store.state.test
}
},
watch: {
getStoreItem () {
console.log(this.$store.state.test,'asfas fas fas')
}
},
子组件监听props变化
参考资料
vue props 传值 触发事件方法
子组件
props:{show:Boolean}
watch:{
show:function(indexVal, oldVal){
console.log(indexVal, oldVal)
}
}
watch:{
show:function(indexVal, oldVal){
console.log(indexVal, oldVal)
}
}
注意
watch不能监听$refs的变化
deep监听
参考资料
vue中computed和watch,方法的区别以及deep,immediate
vue中watch监听器的用法,deep、immediate、flush
实例
export default {
watch: {
someObject: {
handler(newValue, oldValue) {
// 注意:在嵌套的变更中,
// 只要没有替换对象本身,
// 那么这里的 `newValue` 和 `oldValue` 相同
},
deep: true
}
}
}
watch: {
someObject: {
handler(newValue, oldValue) {
// 注意:在嵌套的变更中,
// 只要没有替换对象本身,
// 那么这里的 `newValue` 和 `oldValue` 相同
},
deep: true
}
}
}
父子组件双向数据绑定
参考资料
Vue 父子组件实现数据双向绑定效果的两种方式
v-model
参考资料
vue中的v-model绑定数据深层次问题
父组件调用子组件函数
参考资料
vue3父组件调用子组件的方法
使用ref
this.$refs.refName.method
子组件调用父组件函数
参考资料
Vue中子组件调用父组件的三种方法
vue项目中子组件调用父组件函数报错“TypeError: “this.$parent.b(p)“ is not a function
this.$parent.methodName()
每多嵌套一个element组件需要多用一个$parent
computed
参考资料
12 计算属性computed: 当计算属性依赖的内容发生变更时,才会重新执行计算
原理
缓存,依赖的数据没有变化就不会重新计算
实例
computed: {
// a computed getter
publishedBooksMessage() {
// `this` points to the component instance
return this.author.books.length > 0 ? 'Yes' : 'No'
}
}
// a computed getter
publishedBooksMessage() {
// `this` points to the component instance
return this.author.books.length > 0 ? 'Yes' : 'No'
}
}
何时更新
当我显示运行this.author.books = something_new的时候会重新计算
监听实例
参考资料
vue的computed没有引用就不生效怎么解决?
Vue2官方文档 计算属性和侦听器
vue 中 watch 的使用
Vue 3 官方文档 Computed
监听窗口大小变化
参考资料
VueJs 监听 window.resize 方法
不需要watch,直接看下面这个
vue监听浏览器窗口大小变化
实例
mounted() {
this.screenWidth = document.body.clientWidth;
this.screenHeight = document.body.clientHeight;
window.onresize = () => {
return (() => {
this.screenWidth = document.body.clientWidth;
this.screenHeight = document.body.clientHeight;
})();
};
}
this.screenWidth = document.body.clientWidth;
this.screenHeight = document.body.clientHeight;
window.onresize = () => {
return (() => {
this.screenWidth = document.body.clientWidth;
this.screenHeight = document.body.clientHeight;
})();
};
}
监控滚动位置
参考资料
How to Listen to the Window Scroll Event in a Vue.js Component?
<template>
<div id="app">
<p v-for="n of 100" :key="n">{{ n }}</p>
</div>
</template>
<script>
export default {
name: "App",
created() {
window.addEventListener("scroll", this.handleScroll);
},
unmounted() {
window.removeEventListener("scroll", this.handleScroll);
},
methods: {
handleScroll(event) {
console.log(window.scrollY);
},
},
};
</script>
<div id="app">
<p v-for="n of 100" :key="n">{{ n }}</p>
</div>
</template>
<script>
export default {
name: "App",
created() {
window.addEventListener("scroll", this.handleScroll);
},
unmounted() {
window.removeEventListener("scroll", this.handleScroll);
},
methods: {
handleScroll(event) {
console.log(window.scrollY);
},
},
};
</script>
监听键盘事件
参考资料
vuejs键盘事件不生效解决方式
Vue 3官方文档
监听双击
参考资料
Vue双击点击事件
<a v-on:dblclick="doubleclick">双击a标签</a>
监听右击
参考资料
vue鼠标右击事件@contextmenu.prevent
<div @contextmenu.prevent="rightClick"></div>
阻止浏览器默认事件,添加自定义事件
监听blur
参考资料
Vue进阶(八十七):VUE输入框事件监听blur与change的差异
监听hover事件
参考资料
vue的hover鼠标悬停hover事件
Vue的hover事件
vue中没有hover,可以使用css伪类:hover 或者
@mouseenter @mouseleave @mouseover
@mouseout 等处理类似需求
@mouseenter @mouseleave @mouseover
@mouseout 等处理类似需求
@mouseenter="mouseover" @mouseleave="mouseLeave"
等待 nextTick
参考资料
vue中的nexttick
03-03 组件基础 -
数据交互
数据交互
参考资料
Vue3 Props
Vue2 Prop
关于命名
props里面使用驼峰命名,父组件传参使用-命名
父组件向子组件传值
父组件
属性值传值
固定传值
参数类型:传递的是string类型
<menu-item title="来自父组件的数据"></menu-item>
没有冒号
绑定传值
参数类型:传递的是对应类型的数据
<menu-item :title="title"></menu-item>
有冒号
子组件
props接收
命名规范
html属性名是case-insensitive的,但字符串模板中可以使用驼峰式html属性
基本使用
Vue.component('menue-item',{
props:['title'],
template:'<div>{{title}}</div>',
})
另一种“数据”传递
具名插槽
<template slot="header"></template>
<slot name="header"></slot>
作用域插槽
子组件向父组件传值
参考资料
VUE 子组件向父组件传值(含传多值以及添加额外参数场景)
子组件通过自定义事件向父组件传值
<button @click='$emit("enlarge-text")'>扩大父组件中字体大小</button>
父组件监听自定义属性处理子组件传值
<menu-item :parr='parr' @enlarge-text='handle'></menu-item>
带参数传值
兄弟组件之间传值
创建事件中心通信
var hub = new Vue();
组件监听
Vue.component('test-tom', {
.....
mounted: function() { // 监听事件
hub.$on('tom-event', (val) => {
this.num += val;
});
}
hub.$on('tom-event', (val) => {
this.num += val;
});
}
......
}
事件触发
handle: function(){
// 触发兄弟组件的事件
hub.$emit('tom-event', 1);
}
},
Vue.component('test-jerry', {
......
methods: {handle: function(){
// 触发兄弟组件的事件
hub.$emit('tom-event', 1);
}
},
......
}
事件销毁
var vm = new Vue({
el: '#app',
data: {
},
methods: {
handle: function(){
hub.$off('tom-event');
hub.$off('jerry-event');
}
}
});
el: '#app',
data: {
},
methods: {
handle: function(){
hub.$off('tom-event');
hub.$off('jerry-event');
}
}
});
03-04 组件基础 -
HTML模块
HTML模块
模板
模板内容可以是模板字符串
根元素必须是单个的
原因没太搞懂
插槽
参考资料
Vue 插槽(slot)详细介绍(对比版本变化,避免踩坑)
Vue中slot的常见用法
vue插槽(slot)详解
具名插槽
子组件
//子组件 : (假设名为:ebutton)
<template>
<div class= 'button'>
<button> </button>
<slot name= 'one'> 这就是默认值1</slot>
<slot name='two'> 这就是默认值2 </slot>
<slot name='three'> 这就是默认值3 </slot>
</div>
</template>
<template>
<div class= 'button'>
<button> </button>
<slot name= 'one'> 这就是默认值1</slot>
<slot name='two'> 这就是默认值2 </slot>
<slot name='three'> 这就是默认值3 </slot>
</div>
</template>
父组件
/父组件:(引用子组件 ebutton)
<template>
<div class= 'app'>
<ebutton>
<template v-slot:one> 这是插入到one插槽的内容 </template>
<template v-slot:two> 这是插入到two插槽的内容 </template>
<template v-slot:three> 这是插入到three插槽的内容 </template>
</ebutton>
</div>
</template>
<template>
<div class= 'app'>
<ebutton>
<template v-slot:one> 这是插入到one插槽的内容 </template>
<template v-slot:two> 这是插入到two插槽的内容 </template>
<template v-slot:three> 这是插入到three插槽的内容 </template>
</ebutton>
</div>
</template>
03-05 组件基础 -
动态组件
动态组件
contenteditable
插入vue组件
插入vue组件
参考资料
vue, how dynamically, programically, on click add component to the DOM specific place?
如何将 vue 组件插入 contenteditable div
vue3.x 动态创建组件
Vue3动态实例化组件(自定义弹窗)
参考代码
插入contenteditable
- vue2需要调整
- vue2需要调整
addContainer() {
// dynamically create component, replace 'Child' with your component
var ComponentClass = Vue.extend(Child);
var instance = new ComponentClass();
instance.$mount();
// get the caret position and insert component at that place
var sel, range;
if (window.getSelection) {
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
range.deleteContents();
range.insertNode(instance.$el);
// remove the highlight (if you want)
window.getSelection().removeAllRanges();
}
}
}
// dynamically create component, replace 'Child' with your component
var ComponentClass = Vue.extend(Child);
var instance = new ComponentClass();
instance.$mount();
// get the caret position and insert component at that place
var sel, range;
if (window.getSelection) {
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
range.deleteContents();
range.insertNode(instance.$el);
// remove the highlight (if you want)
window.getSelection().removeAllRanges();
}
}
}
实例 - 父组件
//实例化组件
let pop = createApp(Popup,{
{getLines:getLines}//传递参数(方法)
});
//传递参数(数值)
pop.provide('test', 123);
//使用组件
pop.use(ElementPlus)
//创建dom,及即组件容器
const parent = document.createElement('div');
const component= pop.mount(parent);
//设置弹窗内容
infoWin.setContent(component.$el);
let pop = createApp(Popup,{
{getLines:getLines}//传递参数(方法)
});
//传递参数(数值)
pop.provide('test', 123);
//使用组件
pop.use(ElementPlus)
//创建dom,及即组件容器
const parent = document.createElement('div');
const component= pop.mount(parent);
//设置弹窗内容
infoWin.setContent(component.$el);
实例 - 子组件
export default{
name: 'map-pop',
props:{
getLines:{
type:Function
}
},
setup (props) {
//接受参数
const test=inject('test');
//调用父组件查看轨迹方法
function getLine(data){
props.getLines(data)
}
return {test,getLine}
},
}
export default{
name: 'map-pop',
props:{
getLines:{
type:Function
}
},
setup (props) {
//接受参数
const test=inject('test');
//调用父组件查看轨迹方法
function getLine(data){
props.getLines(data)
}
return {test,getLine}
},
}
成功代码
import {createApp} from "vue"
import TeXBox from "@/contentbox/TeXBox";
import TeXBox from "@/contentbox/TeXBox";
insertTeXBox(formula = ""){
let texBox = createApp(TeXBox,{
});
texBox.provide("formula", formula);
const parent = document.createElement('div');
const component= texBox.mount(parent);
// get the caret position and insert component at that place
let sel, range;
if (window.getSelection) {
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
range.deleteContents();
range.insertNode(component.$el);
// remove the highlight (if you want)
window.getSelection().removeAllRanges();
}
}
}
let texBox = createApp(TeXBox,{
});
texBox.provide("formula", formula);
const parent = document.createElement('div');
const component= texBox.mount(parent);
// get the caret position and insert component at that place
let sel, range;
if (window.getSelection) {
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
range.deleteContents();
range.insertNode(component.$el);
// remove the highlight (if you want)
window.getSelection().removeAllRanges();
}
}
}
Vue相关库
项目与配置管理
参考资料
vue-cli是什么?和 webpack是什么关系?
Vite 与 Vue Cli 对比 - 尤雨溪: Vite 会取代 vue-cli 吗?
Vue Cli
官网
自动为我们生成一个项目结构,vue-cli 里面包含了webpack, 并且配置好了基本的webpack打包规则。
vite
官网
模块化管理与打包
Webpack
Rollup
JS包管理
参考资料
node.js,npm,vue-cli,webpack前端环境和工具的关系
npm 的 --save 选项
npm/yarn 安装依赖时 -S -D -g 的区别详解
npm
node.js
yarn
Vue库概览
参考资料
17个最流行的 Vue 插件
路由管理
Vue-router
压缩
参考资料
vue 代码压缩优化方式_vue.js
vue-cli-plugin-compression
NPM官网
vue.config.js
const zlib = require("zlib");
module.exports = {
pluginOptions: {
compression:{
brotli: {
filename: '[file].br[query]',
algorithm: 'brotliCompress',
include: /\.(js|css|html|svg|json)(\?.*)?$/i,
compressionOptions: {
params: {
[zlib.constants.BROTLI_PARAM_QUALITY]: 11,
},
},
minRatio: 0.8,
},
gzip: {
filename: '[file].gz[query]',
algorithm: 'gzip',
include: /\.(js|css|html|svg|json)(\?.*)?$/i,
minRatio: 0.8,
}
}
}
}
module.exports = {
pluginOptions: {
compression:{
brotli: {
filename: '[file].br[query]',
algorithm: 'brotliCompress',
include: /\.(js|css|html|svg|json)(\?.*)?$/i,
compressionOptions: {
params: {
[zlib.constants.BROTLI_PARAM_QUALITY]: 11,
},
},
minRatio: 0.8,
},
gzip: {
filename: '[file].gz[query]',
algorithm: 'gzip',
include: /\.(js|css|html|svg|json)(\?.*)?$/i,
minRatio: 0.8,
}
}
}
}
状态管理
参考资料
Vue中使用cookies
概念区分
参考资料
各种本地存储对比 cookie,localStorage,sessionStorage,indexDB以及他们和vuex的区别
cookie和localStorage详解
cookie
用于保存每次与服务器端通信都会使用的内容
主要用于标识与验证用户
localStorage
相同浏览器不同页面之间可以共享localStorage
关闭浏览器/页面不会被清楚
sessionStorage
相同浏览器不同页面之间无法共享sessionStorage信息
关闭浏览器/页面会被清除
vuex
运行在内存
localStorage无法像vuex一样实时监控数据的变化使不同组件同时对数据的变化做出反应
应用场景
cookie用于标识用户与安全控制
sessionStorage用于敏感账号一次性登录
sessionStorage与server Session
sessionStorage是client端的储存的东西
server Session是server端存储的东西
server Session通过只给client一个sessionToken来映射每次请求对应的用户
server Session里面的数据对于client不可见,client也无法更改,保证了安全性
cookie其实是由后端设置的!!!
见典型应用 - 自动登录
Vue Cookies
Vuex
Vuex Persisted State
Github
vue持久化存储
数据通讯
Vue - Axios
序列化 - qs
参考资料
QS中文文档
qs库的使用
简单使用
export const adminLogin = (username, password) => {
return axios.post("/loginbackstage", Qs.stringify({ username, password }));
};
return axios.post("/loginbackstage", Qs.stringify({ username, password }));
};
UI组件库
参考资料
12个不容错过的Vue UI 组件库
富文本编辑器
参考资料
在 Vue 项目中引入 tinymce 富文本编辑器
vue中使用v-html 加载富文本
vue中使用vue-quill-editor富文本编辑器,自定义toolbar修改工具栏options
Mint-UI
Element-UI
Vue 2.0组件库
Vue 2.0组件库
Element Plus
Vue 3.0组件库
Vue 3.0组件库
Material Design Icons
Buefy
参考资料
官方文档
下载
npm
npm install buefy
yarn
yarn add buefy
开始
添加一行,头部导入
import Buefy from "buefy";
添加一行,注册
Vue.use(Buefy);
Vuetify
参考资料
官网
Vue 表单工具组件
拖拽
参考资料
Vue+Element树形表格实现拖拽排序示例
Vue利用draggable实现多选拖拽效果
Vue Draggable - 拖拽排序
Vue 2
Vue 3
Sortable.js
Vue Draggable 是 Sortable.js 这个大公司旗下的
LESS&SASS
参考资料
Vue style 深度作用选择器 >>> 与 /deep/(sass/less)
LESS安装
参考资料
安装less 和 less-loader 命令:yarn add less less-loader --dev
yarn add less less-loader --dev
LESS语法
less里面不能用//做注释,//做注释那一行还是会运行
要用/* */
SCSS安装
参考资料
如何在vue用scss
scss在Vue中的安装及使用
npm
npm install node-sass --save-dev //安装node-sass
npm install sass-loader --save-dev //安装sass-loader
npm install style-loader --save-dev //安装style-loader 有些人安装的是 vue-style-loader 其实是一样的!
yarn
yarn add node-sass --dev
yarn add sass-loader --dev
yarn add style-loader --dev
其他支持库
ES高级语法支持
参考资料
Vue中关于Babel的作用和用法解释
一口(很长的)气了解 babel
babel
把 JavaScript 中 es2015/2016/2017/2046 的新语法转化为 es5,
让低端运行环境(如浏览器和 node )能够认识并执行。
让低端运行环境(如浏览器和 node )能够认识并执行。
代码语法格式
参考资料
ESLint在Vue中的使用
什么是ESLint?
eslint
用来识别 ECMAScript/JavaScript 并且按照规则给出报告的代码检测工具
让程序员在编码的过程中发现问题,而不是在执行的过程中发现问题。
其他功能库
地图库
vue-baidu-map
百度地图
百度地图
参考资料
github项目地址
中文文档
百度地图官网
下载
yarn
yarn add vue-baidu-map
npm
npm install vue-baidu-map
开始
添加一行,头部导入
import BaiduMap from 'vue-baidu-map'
添加一行,注册
Vue.use(BaiduMap, {ak:'此处粘贴百度地图ak'})
使用
参考资料
快速上手Vue+百度地图
地图
<template>
<baidu-map id="allmap" @ready="mapReady">
</baidu-map>
</template>
<script>
export default {
name: "Map",
methods:{
mapReady({ BMap, map }) {
// 选择一个经纬度作为中心点
this.point = new BMap.Point(-0.1,51.50);
map.centerAndZoom(this.point, 13);
},
}
}
</script>
<style scoped>
/* 设定地图的大小 */
#allmap{
background-color: aliceblue;
height: 80vh;
width: 98vw;
margin: 0 auto;
}
</style>
<baidu-map id="allmap" @ready="mapReady">
</baidu-map>
</template>
<script>
export default {
name: "Map",
methods:{
mapReady({ BMap, map }) {
// 选择一个经纬度作为中心点
this.point = new BMap.Point(-0.1,51.50);
map.centerAndZoom(this.point, 13);
},
}
}
</script>
<style scoped>
/* 设定地图的大小 */
#allmap{
background-color: aliceblue;
height: 80vh;
width: 98vw;
margin: 0 auto;
}
</style>
自定义覆盖库
多媒体
音频
参考资料
在Vue项目中用Audio实现语音的播放
vue自定义音频audio样式及操作面板
移动端适配
禁止移动端双击和缩放
参考资料
【vue】h5移动端禁止双击和缩放
在index.html中
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover, user-scalable=0">
在app.vue中
created() {
// 禁止页面缩放
window.onload = function () {
document.addEventListener("touchstart", function (event) {
if (event.touches.length > 1) {
event.preventDefault();
}
});
document.addEventListener("gesturestart", function (event) {
event.preventDefault();
});
};
},
// 禁止页面缩放
window.onload = function () {
document.addEventListener("touchstart", function (event) {
if (event.touches.length > 1) {
event.preventDefault();
}
});
document.addEventListener("gesturestart", function (event) {
event.preventDefault();
});
};
},
阻止下拉刷新
参考资料
vueiOS移动端点击input框页面放大问题
移动端网页禁止下拉刷新css
CSS
body {
overscroll-behavior-y: contain;
}
overscroll-behavior-y: contain;
}
没有一个方案可以成功。。。。
禁止滑到最下面还可以上滑
在app.vue设置overflow: hidden
同时也要动态计算body的height,不然所有子元素overflow都将会失效
同时#app也必须设置高度为100%
定义函数
window.addEventListener("resize", resetHeight);
body
监听
function resetHeight(){
// reset the body height to that of the inner browser
document.body.style.height = window.innerHeight + "px";
}
// reset the body height to that of the inner browser
document.body.style.height = window.innerHeight + "px";
}
页面初始化
resetHeight();
input focus
页面缩放问题
页面缩放问题
参考资料
IOS唤起键盘,移动端页面放大
Disable Auto Zoom in Input "Text" tag - Safari on iPhone
CSS
input{
transform: scale(0.875);
transform-origin: left center;
margin-right: -14.28%;
}
transform: scale(0.875);
transform-origin: left center;
margin-right: -14.28%;
}
虚拟DOM
参考资料
CSDN - vue虚拟DOM详解
简书 - 使用虚拟dom和真实dom的区别
CSDN - 什么是虚拟DOM
虚拟DOM
解决的问题
解决的问题
在一次操作中,我需要更新10个DOM节点,浏览器收到第一个DOM请求后并不知道还有9次更新操作,
因此会马上执行流程,最终执行10次。第一次计算完,紧接着下一个DOM更新请求,这个节点的坐标值就变了,
前一次计算为无用功。计算DOM节点坐标值等都是白白浪费的性能。
而虚拟DOM不会立即操作DOM,而是将这10次更新的diff内容保存到本地一个JS对象中,
最终将这个JS对象一次性attch到DOM树上,再进行后续操作,避免大量无谓的计算量。
因此会马上执行流程,最终执行10次。第一次计算完,紧接着下一个DOM更新请求,这个节点的坐标值就变了,
前一次计算为无用功。计算DOM节点坐标值等都是白白浪费的性能。
而虚拟DOM不会立即操作DOM,而是将这10次更新的diff内容保存到本地一个JS对象中,
最终将这个JS对象一次性attch到DOM树上,再进行后续操作,避免大量无谓的计算量。
Vue2使用
参考资料
CSDN - 虚拟DOM(vue、react)中key的作用
这个refName就是组件key的值
this.$ref.refName
Vue3使用
参考资料
vue3官方文档 - Template Refs
vue 3.0 使用ref获取dom元素
vue3中获取dom元素和操作
JS通过变量访问对象属性
定义ref
<div ref="refName"></div>
使用
this.$refs.refName
变量访问
this.$refs[variableRefName]
访问ref的
data与函数
data与函数
参考资料
Vue中ref的三种用法
data
this.$refs.refName.dataName
method
this.$refs.refName.methodName
v-for无法
动态绑定ref
动态绑定ref
参考资料
vue组件的v-for循环中动态绑定ref
解决方法
不使用动态绑定,然后使用数组下标访问
语法
<div v-for="item in list" :ref="xxx"></div>
this.$refs.xxx[0]
this.$refs.xxx[0]
示例
<!-- template -->
<li v-for="(list, index) in tagList" :key="index" ref="tagItem">{{list.value}}</li>
<!-- script -->
this.$refs.tagItem[0].style.backgroundImage = `url(${xxx})`
<li v-for="(list, index) in tagList" :key="index" ref="tagItem">{{list.value}}</li>
<!-- script -->
this.$refs.tagItem[0].style.backgroundImage = `url(${xxx})`
多个同名ref
参考资料
Vue单文件组件中多个同名的ref属性,this.$refs的取值及其使用注意事项
ref数组
参考资料
Vue中ref的绑定与获取(静态、动态)
实例
<!-- :ref="'menuItem'+变量"-->
<div :ref="'menuItem'+index" class="menu_item" v-for="(item,index) in menuData" :key="item.id" @click="clickMenu(index)">
<div class="menu_item_title">
{{item.name}}
</div>
</div>
<div :ref="'menuItem'+index" class="menu_item" v-for="(item,index) in menuData" :key="item.id" @click="clickMenu(index)">
<div class="menu_item_title">
{{item.name}}
</div>
</div>
export default {
name: 'demo',
components: {},
data() {
return {
menuData: [
{id: '0001', name: '菜单一'},
{id: '0002', name: '菜单二'},
{id: '0003', name: '菜单三'},
],
}
},
watch: {},
computed: {},
created() {
},
mounted() {
console.log(this.$refs);
},
methods: {
clickMenu: function (index) {
//this.$refs[`menuItem${index}`]是个数组
console.log("点击了", this.$refs[`menuItem${index}`][0]);
}
}
}
name: 'demo',
components: {},
data() {
return {
menuData: [
{id: '0001', name: '菜单一'},
{id: '0002', name: '菜单二'},
{id: '0003', name: '菜单三'},
],
}
},
watch: {},
computed: {},
created() {
},
mounted() {
console.log(this.$refs);
},
methods: {
clickMenu: function (index) {
//this.$refs[`menuItem${index}`]是个数组
console.log("点击了", this.$refs[`menuItem${index}`][0]);
}
}
}
Composition
与函数式编程
与函数式编程
官网
Composition API FAQ
参考资料
vue3 为什么要使用composition函数式编程
对比React的hooks与Vue的composition
源码泄露问题
参考资料
为什么某些用 vue.js 创建的 web 应用,直接用 chrome 的检查工具就能直接看到项目源码?
vue source-map设置,@符号使用
module.exports = {
//在实际发布的时候,建议将devtool的值设置为nosources-source-map或者关闭sourceMAP
devtool:'nosources-source-map',
}
//在实际发布的时候,建议将devtool的值设置为nosources-source-map或者关闭sourceMAP
devtool:'nosources-source-map',
}
常见问题
移动端overflow失效
可能是body没有加overflow:hidden
单双击冲突
参考资料
Vue中,当组件同时注册单机事件(@click)和双击事件(@dblclick)时,处理事件冲突
应用场景 -
双击重命名
双击重命名
html
<span :contenteditable="editable" @dblclick="setEditableDefinite"
style="height: 20px; padding: 5px;" @blur="renameAndSetNotEditable"
@keydown.enter.exact="renameAndSetNotEditable" @click="setEditable"
>{{ directoryGroup.groupName }}</span>
style="height: 20px; padding: 5px;" @blur="renameAndSetNotEditable"
@keydown.enter.exact="renameAndSetNotEditable" @click="setEditable"
>{{ directoryGroup.groupName }}</span>
Script
setEditable() {
if (!this.clickedOnce&&!this.editable) {
this.editable = true;
this.timer = setTimeout(() => {
this.editable = false
this.clickedOnce = false;
}, 1000);
this.clickedOnce = true;
}else{
this.clickedOnce = false;
}
},
setEditableDefinite() {
clearTimeout(this.timer);
},
renameAndSetNotEditable() {
this.editable = false;
},
if (!this.clickedOnce&&!this.editable) {
this.editable = true;
this.timer = setTimeout(() => {
this.editable = false
this.clickedOnce = false;
}, 1000);
this.clickedOnce = true;
}else{
this.clickedOnce = false;
}
},
setEditableDefinite() {
clearTimeout(this.timer);
},
renameAndSetNotEditable() {
this.editable = false;
},
$store没有高亮
webstorm在使用:class和
向子组件传递参数:parameter的时候
使用this.$store没有变色,
其实是能够成功获取到值的,不用担心
向子组件传递参数:parameter的时候
使用this.$store没有变色,
其实是能够成功获取到值的,不用担心
div没有keydown事件
参考资料
前端杂症--div等容器keydown事件无效(包括vue的@keydown)
vue拖拽@drop不生效解决方式
参考资料
vue拖拽@drop不生效解决方式
需要加上@dragover="e=>e.preventDefault()"
<div class="components-right" @dragover="e=>e.preventDefault()" @drop="onDrop">
Vue3注意
参考资料
vue3没有this怎么办?
vue3没有this了???
模块化
参考资料
vue中html、css、js 分离
分离vue文件中css、js代码的简单技巧
js
<script>
import spacehomejs from './spacehome'
export default spacehomejs
</script>
import spacehomejs from './spacehome'
export default spacehomejs
</script>
只有上面这种方法才能在Idea中正确索引每一个变量和函数,同时不影响页面的渲染
CSS
<style lang="scss" scoped>
@import './index.scss';
</style>
@import './index.scss';
</style>
不能处理v-bind的语法,需要单独写在style里面
0 条评论
下一页