前言

本文是平时遇到的技术问题和学习到的新知识,还未有时间归类整理,放在该文章中记录。
都是比较重要的知识点!!!


i18国际化

一个Vue.js插件,提供了多语言解决方案 项目地址(暂未使用过)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// 安装
npm install vue-i18n --save
// main.js使用
import VueI18n from 'vue-i18n';
Vue.use(VueI18n);

// vue-i18n插件需要在入口文件中进行多语言包配置,其实是一个对象每种语言对应一个key。
const messages = {
en: {
message: {
hello: 'hello world'
}
},
cn: {
message: {
hello: '你好,世界'
}
}
}
const i18n = new VueI18n({
locale: 'en', // 设置当前语言
messages, // 设置语言包
})

new Vue({
el: '#app',
router: router,
i18n: i18n,
render: h => h(App)
});

// 组件中使用
// index.vue
<template>
<div class="index">
<p>{{ $t("message.hello") }}</p>
</div>
</template>

git拉去分支代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
git clone // 克隆项目
git branch // 查看分支
git branch -a // 查看全部分支
// 创建本地分支并与远程分支同步
git checkout -b 本地分支 origin/远程分支

// 注意:在新建分支的时候代码和主分支是一样的
// 新建仓库:git checkout -b dev
// 连接仓库:git push -u origin "dev"

// 只克隆分支 git clone -b dev 地址

// 解决冲突
// 先pull、如果失败则先提交本地代码
// git stash储存、git pull、git stash pop、解决冲突

// 本地新建分支只同步origin的分支(不克隆)
git pull origin dev // 连接好仓库后,先记得要pull
git push -u origin dev // 与git push origin dev 区别是加了-u下次就直接push不需要指定

vue-admin的node-sass安装失败

1
2
3
4
5
6
7
8
9
10
11
// 全局安装
npm install --registry=https://registry.npm.taobao.org
// 先卸载node-sass,再使用cnpm
npm uninstall node-sass
// 对比框架node-sass版本,复制node-sass的配置到package.json中
cnpm install

// ------------------
// 但是node-sass的版本有点变化
npm i node-sass --sass_binary_site=https://npm.taobao.org/mirrors/node-sass
npm install --registry=https://registry.npm.taobao.org

export导入导出一体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// a.js文件
export let a = 1
export let b = 2
// b.js文件(统一导出)export from
export {a as c, b} from './a.js'
// HTML文件中,注意HTML使用时<script type="module"><script>
<script type="module">
import {c, b} from './b.js'
console.log(c, b) // 1 2
</script>

// ----------
// 可能的config配置extensions: ['.js', '.vue', '.json'],
// 在import中省略后缀(注意json不能省略)
export { default as a } from './a'
// 如果a是一个文件夹
// 则先找package.json、index.js、index.vue

// 如果a不是
// 则先找同名json、js、vue

单点登录


使用弹力盒子是多个flex布局时会出现宽度不自适应

1
2
3
4
5
6
max-width: 1000px;
width: 100%;

// 或者
max-width: 100%;
width: 1000px;

npm 和 yarn配置镜像源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// npm(安装前三个就够用了)
npm config set registry=https://registry.npm.taobao.org
npm config set sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
npm config set phantomjs_cdnurl=https://npm.taobao.org/mirrors/phantomjs/
npm config set electron_mirror=https://npm.taobao.org/mirrors/electron/
// yarn(安装前三个就够用了)
yarn config set registry https://registry.npm.taobao.org --global
yarn config set disturl https://npm.taobao.org/dist --global
yarn config set sass_binary_site https://npm.taobao.org/mirrors/node-sass --global
yarn config set electron_mirror https://npm.taobao.org/mirrors/electron/ --global
yarn config set puppeteer_download_host https://npm.taobao.org/mirrors --global
yarn config set chromedriver_cdnurl https://npm.taobao.org/mirrors/chromedriver --global
yarn config set operadriver_cdnurl https://npm.taobao.org/mirrors/operadriver --global
yarn config set phantomjs_cdnurl https://npm.taobao.org/mirrors/phantomjs --global
yarn config set selenium_cdnurl https://npm.taobao.org/mirrors/selenium --global
yarn config set node_inspector_cdnurl https://npm.taobao.org/mirrors/node-inspector --global

yarn和npm命令对比

npm yarn
npm install yarn
npm install react --save yarn add react
npm uninstall react --save yarn remove react
npm install react --save-dev yarn add react --dev
npm update --save yarn upgrade
npm install -g @vue/cli yarn global add @vue/cli

vue的$set

1
2
3
4
5
6
7
// 以下方法修改数组会触发视图更新
// push() pop() shift() unshift() splice() sort() reverse()
// vue侦听不到数组的某个值改变,或者对象属性的添加和删除,直接改变数组和对象会影响视图。
// 1.通过索引直接设置项 books[2] = 1
// 但是通过索引修改数组里面的对象值可以 books[2].count = 1
// 2.修改数组长度 books.length = 1
// 解决:使用splice可以解决,使用的$set

原生的match方法

1
2
3
4
5
6
7
8
9
10
11
12
// match方法在字符串内检索指定的值,或找到一个或多个正则表达式的匹配。
// 返回值为:存放匹配结果的数组
var str="Hello world!"
console.log(str.match("world")) // 数组
console.log(str.match("worlld")) // null

// 配合数组filter
var books = ['vue','JavaScript']
books = books.filter(function (item) {
return item.match(/JavaScript/);
});
console.log(books) // ['JavaScript']

vuecli使用webstorm中@快捷跳转不了

  1. 要将node_modules文件接触排除
  2. 设置先禁用webpack,(webstorm -> preference -> language & frameworks -> javascript -> webpack)再次打开重启后在下方事件日志会弹出信任webpack的选项点击确认
  3. 手动选择webpack配置文件,选择(node_modules -> @vue -> cli-service -> webpack.config.js)
  4. 注意可能是没有配置@别名,在vue.config.js(但是新版不用,不是主要原因)

组件的双向绑定

1.父子组件的自定义双向v-model

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 子组件
<template>
<h1>{{ msg }}</h1>
</template>
model:{
prop:'msg', // 指父组件设置 v-model 时,将变量值传给子组件的 msg
event:'parent-event' // 指父组件监听 parent-event 事件
},
props:{
msg:String // 此处必须定义和model的prop相同的props,因为v-model会传值给子组件
},
mounted(){
let newMsg = '新值'
this.$emit('parent-event', newMsg);

}
}
// 父组件只需要使用v-model即可
<children v-model="parentMsg"></children>

2.父子组件的自定义多个双向值.sync

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 子组件
<template><h1>{{ msg }}</h1></template>
props:{
msg:String
},
mounted(){
// 通过$emit,固定字段update:prop名
let newMsg = '新值'
this.$emit('update:msg', newMsg);
}
// 父组件,需在平时常用的单向传值上加上.sync修饰符
<children :msg.sync="parentMsg"></children>
// <children :msg="parentMsg" @update:msg="parentMsg = $event"></children>
// 全部对象简化写法
// <children :.sync="obj"></children>

package.js介绍

参考:https://juejin.cn/post/6987179395714646024

package.json文件是一个JSON对象

写法 版本说明
固定版本(1.1.1) 只安装指定版本
波浪号(~1.1.1) 安装1.1.x最新版本
插入号(ˆ1.1.1) 安装1.x.x的最新版本

注意:当大版本号为0时,插入号的行为与波浪号相同

处于开发阶段,次要版本号变动可能带来程序的不兼容。

1
2
3
4
5
// 项目的dependencies全部更新到最新的版本  --还暂未使用,待确认
npm install -g npm-check-updates // 安装
ncu // 检查package.json中dependencies的最新版本
ncu -u // 更新devDependencies到新版本
ncu -a //更新全部dependencies到最新版本

node中的path的方法

1
2
3
4
5
6
7
// path.join()方法
// 将多个参数字符串合并成一个路径字符串
path.join(__dirname,'src') // 如__dirname为F:/moxie,则F:/moxie/src
// path.resolve()方法
// 是以程序为根目录,作为起点,根据参数解析出一个绝对路径
path.resolve(__dirname, "/src") // /相当于根目录,没有/则和join相同(..与../就是返回)
// 如__dirname为F:/moxie,则F:/src

props数据验证

采用对象写法数据验证,比如某个数据必须是数字类型,如果传入字符串,就会在控制台弹出警告。

type也可以是一个自定义构造器,使用instanceof检测。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Vue.component('my-component', {
props: {
//必须是数字类型
propA: Number,
//必须是字符串或数字类型
propB: [String, Number],
// 布尔值,如果没有定义,默认值就是true
propC: {
type: Boolean,
default: true
},
//数字,而且是必传
propD: {
type: Number,
required: true
},
// 如果是数组或对象,默认值必须是一个函数来返回
propE: {
type: Array,
default: function () {
return [];
}
},
// 自定义一个验证函数
propF: {
validator: function (value) {
return value > 10;
}
}
}
});

jquery的jsonp的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$.ajax({
url: "http://xxx.com?id=xxx" // 请求的的地址(其后面可以带参数)
type: "GET", // 当然参数可以省略
data: { name: 'moxie'}, // 传给服务端的数据,被加载url?的后面
dataType: "jsonp", // 预期服务器返回的数据类型
jsonpCallback: 'globalCallback', // 全局JSONP回调函数名
success: function (data) { // 请求成功之后调用
var result = JSON.stringify(data)
console.log(result);
},
error: function (err) { // 请求出错时调用
console.log(err)
},
complete: function (data) { // 请求完成时调用,无论请求失败或成功。
console.log(data)
}
});
// 全局回调函数的使用
function globalCallback(result) {
console.log(result)
}

具名插槽和作用域插槽一起使用

1
2
3
4
5
6
7
8
9
10
<!-- 子组件的插槽中: msg是要传递给父组件的值 name是该插槽的名字--> 
<slot :msg="message" name="child">默认要显示的内容</slot>

<!-- 父组件child组件标签的template标签上: -->
<child>
<!-- 这里如果直接写成v-slot='scope'则不会生效 页面不会展示数据!-->
<template v-slot:child="{ msg }">
<h2>{{ msg }}</h2>
</template>
</child>

表格的相关样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
table {
width: 100%;
text-align: center;
border-spacing: 0; /**设置相邻单元格的边框间的距离**/
border-collapse: collapse; /**边框会合并为一个单一的边框**/
color: #5a5a5a;
table-layout: fixed; /**固定table表格**/
}
table thead { background-color: #d9edf7; }
table td,table th {
border:1px solid #ccc;
overflow: hidden;/**溢出隐藏**/
white-space: nowrap;/**不换行**/
text-overflow: ellipsis;/**溢出不可见部分使用...代替**/
}

<table>
<caption>我是表格标题</caption>
<!--表头-->
<thead>
<tr>
<th>姓名</th>

</tr>
</thead>
<!--表内容-->
<tbody>
<tr>
<td>测试</td>


</tr>
</tbody>
</table>

禁止生成package-lock.json文件

1
2
npm config set package-lock false
npm config set package-lock true

element ui的表格格式化

1
2
3
4
5
6
7
8
<!--封装列时的格式化数据(formatter)-->
<el-table-column prop="address" label="地址" :formatter="formatter"></el-table-column>
// 方法
formatter(row, column) {
if(column.property==='address'){
return '处理后的值'
}
}

作用域插槽案例

作用:复用模板替换已渲染元素。

如:列表组件中,允许组件自定义应该如何渲染列表每一项。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<div id="app">
<my-list :data="books">
<template v-slot:book="props">
<li>{{ props.bookName }}</li>
</template>
</my-list>
</div>
<script>
Vue.component('my-list', {
props: {
data: {
type: Array,
default: function () {
return [];
}
}
},
template: '<ul><slot name="book" v-for="book in books" :book-name="book.name"></slot></ul>'
});
var app = new Vue({
el: '#app',
data: {
books: [
{ name: '《Vue.js实战》' },
{ name: '《JavaScript高级程序设计》' }
]
}
})
</script>

递归组件

组件在它的模板内可以递归地调用自己,只要给组件设置name的选项就可以了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 父组件
<template>
<div id="app">
<Child :count="0"/>
</template>
<script>
import Child from '@/views/Child'
export default {
name: 'App',
components: { Child },
</script>

// 子组件
// 子组件中需要给定name属性,自己调用自己(注意需要给定结束条件)
// 子组件并没有修改porps的count值,而是每次递归后组件传的count都是不一样的
<template>
<div class="child">
<div>{{ count }}</div>
<Child v-if="count<3" :count="count+1"/>
</div>
</template>
<script>
export default {
name: 'Child',
props: {
count: {
type: Number,
default: 0
}
},
}
</script>

内联模板(vue3移除)

缺点:作用域比较难理解,建议不要轻易使用内联模板。

组件标签使用inline-template特性,组件就会把它的内容当作模板。

父组件里面写内容可以读取到父组件与子组件的数据(如果同名,优先使用子组件的数据)


vue项目的断点调试

使用浏览器devtool中的Sources下,左侧的webpack://目录中,可以找到对应的代码。

重要:在js代码中直接输入debugger浏览器则会直接运行到这里进行断点。


webstorm快捷键

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
下面是Webstorm的一些常用快捷键:
单行代码注释:Ctrl+/
多行注释:Ctrl+Shift+/
格式化代码:Ctrl+Alt+L
复制行:Ctrl+D
删除行:Ctrl+Y
替换文本:Ctrl+R
查找文本:Ctrl+F
代码折叠:Ctrl + 或者Ctrl Shift +
代码展开:Ctrl - 或者 Ctrl Shift -
代码右移:Tab键(快捷生成代码)
代码左移:Shift+TAB
代码上移:Shift+Alt+方向键上
代码下移:Shift+Alt+方向键下
长按Alt+鼠标点击不同处再放掉Alt,可以同时编辑多处

正则表达式中

1
2
3
4
5
6
// 匹配js文件\.(不加的话就是匹配任意一个开头的字符)
const check1 = /.js$/
const check2 = /\.js$/
const str = 'ajs'
console.log(check1.test(str)) // true
console.log(check2.test(str)) // false

vue的Render函数

掘金Render

Virtual Dom并不是真正意义上的DOM,而是一个轻量级的JavaScript对象,在状态发生变化时,Virtual Dom会进行Diff运算,来更新只需要被替换的DOM,而不是全部重绘。

Vue的Render函数和React的一样,也就是jsx,Render函数创建HTML,通过createElement参数来创建Virtual Dom,结构精简。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 使用Render函数构建不同的<h1>~<h6>标签
<div id="app">
<anchored-heading :level="1">Hello world!</anchored-heading>
</div>
Vue.component('anchored-heading', {
render: function (createElement) {
return createElement(
'h' + this.level, // 标签名称
this.$slots.default // 子节点数组
)
},
props: {
level: {
type: Number,
required: true
}
}
})
var app = new Vue({
el: '#app'
})

createElement参数

第1个参数: { String | Object | Function }—-(示例如下)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// String
Vue.component('custom-element', {
render(createElement) {
return createElement('div', 'hello world!')
}
})
// Object
Vue.component('custom-element', {
render(createElement) {
return createElement({
template: `<div>hello world!</div>`
})
}
})
// Function
Vue.component('custom-element', {
render(createElement) {
const elFn = () => ({ template: `<div>hello world!</div>` })
return createElement(elFn())
}
})

vue插件

注册插件需要install方法,第一个参数是Vue构造器,第二个参数是一个可选的选项对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
MyPlugin.install = function (Vue, options) {
// 全局注册组件(指令等功能资源类似)
Vue.component('component-name', {
//组件内容
})
//添加实例方法
Vue.prototype.$Notice = function () {
// 逻辑...
}
//添加全局方法或属性
Vue.globalMethod = function () {
// 逻辑...
}
//添加全局混合
Vue.mixin({
mounted: function () {
// 逻辑...
}
})
}
// ----------

// 通过Vue.use()来使用插件:
Vue.use(MyPlugin)
//或
Vue.use(MyPlugin, {
// 参数
})

vue中央处理事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// 新建vue-bus.js文件
const install = function (Vue) {
const Bus = new Vue({
methods: {
emit (event, ...args) {
this.$emit(event, ...args);
},
on (event, callback) {
this.$on(event, callback);
},
off (event, callback) {
this.$off(event, callback);
}
}
});
Vue.prototype.$bus = Bus;
};
export default {install};


// main.js,部分代码省略
import VueBus from './vue-bus';
Vue.use(VueBus);

// 使用A组件
<template>
<div>
{{ number }}
<button @click="handleAddRandom">随机增加</button>
</div>
</template>
methods: {
handleAddRandom () {
// 随机获取1~100中的数
const num = Math.floor(Math.random () * 100 + 1);
this.$bus.emit('add', num);
}
}

// B组件使用并且监听A组件
<template>
<div>随机增加:
<Counter :number="number"></Counter>
</div>
</template>

import Counter from './counter.vue';

export default {
components: {
Counter
},
methods: {
handleAddRandom(num) {
this.number += num;
}
},
data() {
return {
number: 0
}
},
created() {
this.$bus.on('add', this.handleAddRandom);
},
beforeDestroy() {
this.$bus.off('add', this.handleAddRandom);
}
}
// 需要注意:
// 1. $bus.on应该在created钩子内使用,
// 如果在mounted使用可能接收不到其他组件来自created钩子内发出的事件。
// 2. 使用了$bus.on,在beforeDestroy钩子里应该再使用$bus.off解除,
// 因为组件销毁后,就没必要把监听的句柄储存在vue-bus里了。