--- title: Vue date: 2021-03-23 10:30:31 author: 文永达 --- # Vue ## Vite 官方文档 https://cn.vitejs.dev ### vite.config.js配置 #### src设置@别名 ```javascript import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' const { resolve } = require('path') // https://vitejs.dev/config/ export default defineConfig({ plugins: [vue()], resolve:{ alias:{ '@': resolve('src') } } }) ``` ## vite.config.ts 引入 path 模块注意点 1. 安装`@types/node` 2. 在 `tsconfig.node.json`配置 ```json "compilerOptions": { ... "allowSyntheticDefaultTmports": true } ``` ## Vue CLI ### 安装 ```shell npm install -g @vue/cli yarn global add @vue/cli vue --version ``` ### 升级 ```shell npm upadte -g @vue/cli yarn global upgrade --latest @vue/cli ``` ### 创建一个项目 ```shell vue create hello-world #创建一个名叫 hello-world 的 vue cli项目 ``` ### 配置全局环境变量 .env 全局默认配置文件,不论什么环境都会加载合并 .env.development 开发环境下的配置文件 .env.production 生产环境下的配置文件 属性名必须以VUE_APP_开头 .env.development ```properties VUE_APP_URL='' ``` 文件的加载 根据启动命令vue会自动加载对应的环境,vue是根据文件名进行加载的,所以上面说“不要乱起名,也无需专门控制加载哪个文件” 比如执行npm run serve命令,会自动加载.env.development文件,也有可能是npm run dev,这个得看package.json配置的是啥,具体看下面package.json配置 可通过process.env属性 (全局属性) .env有的,.env.development也有,就会优先.env.development,.env.development没有的,.env有的,就会有.env的 ### vue.config.js配置 #### src设置@别名 ```javascript module.exports = { chainWebpack: config => { config.resolve.alias .set('@', resolve("src")) } } ``` #### 端口设置 ```javascript module.exports = { devServer: { port: 9090 } } ``` #### 跨域代理 ```javascript module.exports = { devServer: { proxy: { '/api': { target: 'http://127.0.0.1:9001', ws: true, changeOrigin: true, pathRewrite: { '^/api': '' } } } } } ``` ### package.json配置 #### 环境配置 ```json { "scripts": { "start": "vue-cli-service serve --open --mode production", "dev": "vue-cli-service serve --open", "build": "vue-cli-service build", "build:prod": "vue-cli-service build --mode production", "lint": "vue-cli-service lint --fix", "upload": "vue-cli-service ssh", "test:unit": "vue-cli-service test:unit", "test:e2e": "vue-cli-service test:e2e --mode development" } } ``` scripts中dev 说明 需要用 npm run dev 来启动开发环境 如果是serve则是 npm run serve,可以手动添加serve ```json "scripts": { "start": "vue-cli-service serve --open --mode production", "dev": "vue-cli-service serve --open", "serve": "vue-cli-service serve --open", "build": "vue-cli-service build", "build:prod": "vue-cli-service build --mode production", "lint": "vue-cli-service lint --fix", "upload": "vue-cli-service ssh", "test:unit": "vue-cli-service test:unit", "test:e2e": "vue-cli-service test:e2e --mode development" } ``` ## EditorConfig 如果使用的是Vscode,先安装插件 `EditorConfig for Visual Studio Code` # Axios ## 安装 ```shell npm install axios yarn add axios ``` ## 创建实例 ```javascript // MyAxios.js import axios from 'axios' const instance = axios.create({ baseURL: 'http://localhost:8080', timeout: 3000 }) export default instance ``` ```javascript // demoApi.js import axios from '@/utils/MyAxios' import Qs from 'qs' export const findList = () => { return axios({ url: '', method: 'get', params: { } }) } export const add = (data) => { return axios({ url: '', method: 'post', //axios默认contentType为application/json springmvc默认是application/x-www-form-urlencoded //需添加请求头 headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, //并且数据需要转换成js对象 data: Qs.stringify(data) }) } ``` # TypeScript ## 基础类型 ### 布尔值 ```typescript let isDone: boolean = false; ``` ### 数字 ```typescript let decLiteral: number = 6; let hexLiteral: number = 0xf00d; let binaryLiteral: number = 0b1010; let octalLiteral: number = 0o744; ``` ### 字符串 ```typescript let name: string = "bob"; name = 'smith'; ``` 还可以使用*模版字符串*,它可以定义多行文本和内嵌表达式。 这种字符串是被反引号包围( ```),并且以`${ expr }`这种形式嵌入表达式 ```typescript let name: string = `Gene`; let age: number = 37; let sentence: string = `Hello , my name is ${ name }. I'll be ${ age + 1 } years old next month.`; ``` 这与下面定义相同 ```typescript let sentence: string = "Hello, my name is " + name + ".\n\n" + "I'll be " + (age + 1) + " years old next month."; ``` ### 数组 可以在元素类型后面接上`[]`,表示由此类型元素组成的一个数组: ```typescript let list: number[] = [1, 2, 3]; ``` 或者 ```typescript let list: Array = [1, 2, 3]; ``` ### 元组 元组类型允许表示一个已知元素类型和类型的数组,各元素的类型不必相同。比如,你可以定义一对值分别为`string`和`number`类型的元组。 ```typescript let x: [string, number]; x = ['hello', 10]; ``` ### 枚举 使用`enum`类型可以为一组数组赋予友好的名字。 ```typescript enum Color {Red, Green, Blue} let c: Color = Color.Green; ``` 默认情况下,从`0`开始为元素编号。 你也可以手动的指定成员的数值。 例如,我们将上面的例子改成从 `1`开始编号: ```typescript enum Color {Red = 1, Green, Blue} let c: Color = Color.Green; ``` 或者,全部都采用手动赋值: ```typescript enum Color {Red = 1, Green = 2, Blue = 4} let c: Color = Color.Green; ``` 枚举类型提供的一个便利是你可以由枚举的值得到它的名字。 例如,我们知道数值为`2`,但是不确定它映射到`Color`的哪个名字,我们可以查找相应的名字: ```typescript enum Color {Red = 1, Green, Blue} let colorName: string = Color[2]; console.log(colorName); // 显示'Green'因为上面代码里它的值是2 ``` ### Any 不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查。 那么可以使用 `any`类型来标记这些变量: ```typescript let notSure: any = 4; notSure = "maybe a string instead"; notSure = false; // okay, definitely a boolean ``` 在对现有代码进行改写的时候,`any`类型是十分有用的,它允许你在编译时可选择地包含或移除类型检查。 你可能认为 `Object`有相似的作用,就像它在其它语言中那样。 但是 `Object`类型的变量只是允许你给它赋任意值 - 但是却不能够在它上面调用任意的方法,即便它真的有这些方法: ```typescript let notSure: any = 4; notSure.ifItExists(); // okay, ifItExists might exist at runtime notSure.toFixed(); // okay, toFixed exists (but the compiler doesn't check) let prettySure: Object = 4; prettySure.toFixed(); // Error: Property 'toFixed' doesn't exist on type 'Object'. ``` 当只知道一部分数据的类型时,`any`类型也是有用的。比如,有一个数组,它包含了不同类型的数据: ```typescript let list: any[] = [1, true, "free"]; console.log(list[1]); // true list[1] = 100; // 100 ``` 比较像元组 ### Void `void`类型与`any`类型相反,它表示没有任何类型。当一个函数没有返回值时,通常会见到其返回类型是`void`: ```typescript function warnUser(): void { console.log("This is my warning message"); } ``` 声明一个`void`类型的变量没有什么大用,因为你只能为它赋予`undefinded`和`null`: ```typescript let unusable: void = undefin ``` # VueRouter # Vuex Vuex是一个专为Vue.js应用程序开发的**状态管理模式**。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。 状态(state)通俗说就是数据(data)。 可用于父子组件数据传值。最主要用于解决兄弟组件数据传值,以往通过将数据存储到localStorage中。 ## 安装 ```shell yarn add vuex ``` ## state state相当于组件中的data,专门用来存放全局的数据 在`src`下创建 `store`文件夹 创建`index.js`文件 ```javascript import { createStore } from 'vuex'; export default createStore({ // state相当于组件中的data,专门用来存放全局的数据 state: { num: 0 }, // getters: {}, // mutations: { increment (state) { state.num++ } }, }) ``` 修改入口文件`main.js` ```javascript import { createApp } from 'vue' import App from './App.vue' // 引入store import store from '@/store' createApp(App).use(store).mount('#app') ``` 在`src`下创建`views`文件夹 创建`About.vue` ```vue ``` 创建`Home.vue` ```vue ``` 在`components`文件夹下创建`Btn.vue` ```vue ``` 修改主组件`App.vue` ```vue ``` ## getters getters相当于组件中的computed,getters是全局的,computed是组件内部的 修改`index.js` ```javascript // 在store(仓库)下的index.js这份文件,就是用来做状态管理的 // import Vuex from 'vuex'; import { createStore } from 'vuex'; export default createStore({ // state相当于组件中的data,专门用来存放全局的数据 state: { num: 0 }, // getters相当于组件中的computed,getters是全局的,computed是组件内部的 getters: { getNum(state) { return state.num } }, // mutations: { increment (state) { state.num++ } }, }) ``` 修改`About.vue` ```vue ``` ## mutations mutations相当于组件中的methods,但是它不能使用异步方法(定时器、axios) 修改`index.js` ```javascript // 在store(仓库)下的index.js这份文件,就是用来做状态管理的 // import Vuex from 'vuex'; import { createStore } from 'vuex'; export default createStore({ // state相当于组件中的data,专门用来存放全局的数据 state: { num: 0 }, // getters相当于组件中的computed,getters是全局的,computed是组件内部的 getters: { getNum(state) { return state.num } }, //mutations相当于组件中的methods,但是它不能使用异步方法(定时器、axios) mutations: { increment (state, payload) { state.num+=payload ? payload : 1 } }, }) ``` 修改`Btn.vue` ```vue ``` ## actions actions专门用来处理异步,实际修改状态值的,依然是mutations 修改`index.js` ```javascript // 在store(仓库)下的index.js这份文件,就是用来做状态管理的 // import Vuex from 'vuex'; import { createStore } from 'vuex'; export default createStore({ // state相当于组件中的data,专门用来存放全局的数据 state: { num: 0 }, // getters相当于组件中的computed,getters是全局的,computed是组件内部的 getters: { getNum(state) { return state.num } }, //mutations相当于组件中的methods,但是它不能使用异步方法(定时器、axios) mutations: { increase (state, payload) { state.num += payload ? payload : 1 }, clear (state) { state.num = 0 }, decrease (state, payload) { if (state.num === 0) { state.num = 0 } else { state.num -= payload ? payload : 1 } } }, // actions专门用来处理异步,实际修改状态值的,依然是mutations actions: { decreaseAync (context, num) { context.commit('decrease', num) } } }) ``` 修改`Btn.vue` ```vue ``` # Pug.js Pug(之前称为Jade)是一种简洁而灵活的模板引擎,用于构建HTML。Pug使用缩进和标记替代了常见的HTML标记,这使得它更易于阅读和编写。它也提供了一些功能,如变量、循环和条件语句等,可以帮助开发人员更轻松地构建动态的网页。 ## 特性 ### 属性 如果一个标签有多个属性,可使用 分行 或 逗号 ```less // 1 el-button(v-if="ifShow" type="size" size="small" @click="doClidk") 点击 // 2 el-button(v-if="ifShow",type="size",size="small",@click="doClidk") 点击 // 3 el-button(v-if="ifShow" type="size" size="small" @click="doClick") 点击 ``` ### 注释 - 单行 ```xml // 一些内容 p foo p bar

foo

bar

``` - 不输出注释 ```less //- 这行不会出现在结果中 p foo p bar

foo

bar

``` - 块注释 ```xml body // 一堆 文字 进行中 ``` ## Vue 2集成Pug.js Vue CLI安装Pug.js ```shell npm i -D pug pug-html-loader pug-plain-loader ``` vue.config.js配置 ```javascript // vue.config.js module.exports = { chainWebpack: config => { config.module.rule('pug') .test(/\.pug$/) .use('pug-html-loader') .loader('pug-html-loader') .end() } } ``` 使用前 ```vue ``` 使用后 ```less ``` # Vben Admin 官方文档 https://vvbin.cn/doc-next/ # D2Admin ## API封装 /src/api ### axios实例 `service.js` ### 自定义API modules目录 `sys.user.api.js` ```javascript // import { find, assign } from 'lodash' // const users = [ // { username: 'admin', password: 'admin', uuid: 'admin-uuid', name: 'Admin' }, // { username: 'editor', password: 'editor', uuid: 'editor-uuid', name: 'Editor' }, // { username: 'user1', password: 'user1', uuid: 'user1-uuid', name: 'User1' } // ] // import Qs from 'qs' const baseURL = '/admin' export default ({ service, request, serviceForMock, requestForMock, mock, faker, tools }) => ({ /** * @description 登录 * @param {Object} data 登录携带的信息 */ SYS_USER_LOGIN (data = {}) { // 模拟数据 // mock // .onAny('/login') // .reply(config => { // const user = find(users, tools.parse(config.data)) // return user // ? tools.responseSuccess(assign({}, user, { token: faker.random.uuid() })) // : tools.responseError({}, '账号或密码不正确') // }) // 接口请求 return request({ url: baseURL + '/login/login', method: 'post', data: data // data: Qs.stringify(data), // headers: { // 'Content-Type': 'application/x-www-form-urlencoded' // } }) }, FIND_USER_LIST (data = {}) { return request({ url: baseURL + '/user/getAll', method: 'post', data: data }) }, REFRESH_MSG () { return request({ url: baseURL + '/user/refreshmsg', method: 'get' }) }, ADD_USER (data = {}) { return request({ url: baseURL + '/user/add', method: 'post', data: data }) }, UPDATE_USER (data = {}) { return request({ url: baseURL + '/user/update', method: 'put', data: data }) }, DELETE_USER_BY_ID (data = {}) { return request({ url: baseURL + '/user/delete', method: 'delete', data: data }) } }) ``` `sys.menu.api.js` ```javascript const baseURL = '/admin' export default ({ request }) => ({ MENU_CURRENT (data = {}) { return request({ url: baseURL + '/menu/get/current/menutree', method: 'get' }) }, ROUTER_CURRENT (data = {}) { return request({ url: baseURL + '/menu/get/current/vuerouter', method: 'get' }) } }) ``` ## 登录逻辑 登录页面 /src/views/system/login/page.vue `page.vue` ```vue ``` /src/store/modules/d2admin/modules/account.js `account.js` ```javascript actions: { /** * @description 登录 * @param {Object} context * @param {Object} payload username {String} 用户账号 * @param {Object} payload password {String} 密码 * @param {Object} payload route {Object} 登录成功后定向的路由对象 任何 vue-router 支持的格式 */ async login ({ dispatch }, { username = '', password = '', to = '/' } = {}) { // 这里axios请求 const res = await api.SYS_USER_LOGIN({ username, password }) // 设置 cookie 一定要存 uuid 和 token 两个 cookie // 整个系统依赖这两个数据进行校验和存储 // uuid 是用户身份唯一标识 用户注册的时候确定 并且不可改变 不可重复 // token 代表用户当前登录状态 建议在网络请求中携带 token // 如有必要 token 需要定时更新,默认保存一天 util.cookies.set('uuid', res.uuid) util.cookies.set('token', res.token) // 设置 vuex 用户信息 await dispatch('d2admin/user/set', { name: res.name }, { root: true }) // 用户登录后从持久化数据加载一系列的设置 await dispatch('load') // 此处执行动态菜单 动态路由 await dispatch('updateCache', { to: to }) }, } ``` ## 动态菜单 修改`main.js`入口文件 ```javascript new Vue({ router, store, i18n, render: h => h(App), created () { // 处理路由 得到每一级的路由设置 this.$store.commit('d2admin/page/init', frameInRoutes) // 设置顶栏菜单 // this.$store.commit('d2admin/menu/headerSet', menuHeader) // 设置侧边栏菜单 // this.$store.commit('d2admin/menu/asideSet', menuAside) // 对于已登录的做菜单,搜索数据处理 this.$store.dispatch('d2admin/menu/get') // 初始化菜单搜索功能 修改搜索数据根据侧边栏还是头部栏 // this.$store.commit('d2admin/search/init', menuAside) }, ``` 注释掉以下 mutation ```javascript // 设置顶栏菜单 // this.$store.commit('d2admin/menu/headerSet', menuHeader) // 设置侧边栏菜单 // this.$store.commit('d2admin/menu/asideSet', menuAside) ``` 所有逻辑在Vuex中完成 到 /src/store/modules/d2admin/modules/menu.js `menu.js` ```javascript // 设置文件 import setting from '@/setting.js' import api from '@/api' import { uniqueId } from 'lodash' // 这是从/src/menu/index.js拿到的方法 负责给菜单空的path加上 d2-menu-empty- #随机数字 需要引入lodash uniqueId function supplementPath (menu) { return menu.map(e => ({ ...e, path: e.path || uniqueId('d2-menu-empty-'), ...e.children ? { children: supplementPath(e.children) } : {} })) } export default { namespaced: true, state: { // 顶栏菜单 header: [], // 侧栏菜单 aside: [], // 侧边栏收缩 asideCollapse: setting.menu.asideCollapse, // 侧边栏折叠动画 asideTransition: setting.menu.asideTransition }, actions: { /** * 设置侧边栏展开或者收缩 * @param {Object} context * @param {Boolean} collapse is collapse */ async asideCollapseSet ({ state, dispatch }, collapse) { // store 赋值 state.asideCollapse = collapse // 持久化 await dispatch('d2admin/db/set', { dbName: 'sys', path: 'menu.asideCollapse', value: state.asideCollapse, user: true }, { root: true }) }, /** * 切换侧边栏展开和收缩 * @param {Object} context */ async asideCollapseToggle ({ state, dispatch }) { // store 赋值 state.asideCollapse = !state.asideCollapse // 持久化 await dispatch('d2admin/db/set', { dbName: 'sys', path: 'menu.asideCollapse', value: state.asideCollapse, user: true }, { root: true }) }, // 以下为生成菜单数据的 action /** * 设置菜单 * @param {*} param0 * @param {*} aside */ async set ({ state, dispatch }, aside) { aside = supplementPath(Array.from(await api.MENU_CURRENT())) state.aside = aside console.log('---set-------') // 持久化 await dispatch('d2admin/db/set', { dbName: 'sys', path: 'menu.aside', value: aside, user: true }, { root: true }) // 搜索 await dispatch('d2admin/search/init', aside, { root: true }) }, // 这个是页面刷新用到的 async get ({ state, dispatch, commit }) { state.aside = await dispatch('d2admin/db/get', { dbName: 'sys', path: 'menu.aside', defaultValue: [], user: true }, { root: true }) commit('asideSet', state.aside) // 搜索 await dispatch('d2admin/search/init', state.aside, { root: true }) }, /** * 设置侧边栏折叠动画 * @param {Object} context * @param {Boolean} transition is transition */ async asideTransitionSet ({ state, dispatch }, transition) { // store 赋值 state.asideTransition = transition // 持久化 await dispatch('d2admin/db/set', { dbName: 'sys', path: 'menu.asideTransition', value: state.asideTransition, user: true }, { root: true }) }, /** * 切换侧边栏折叠动画 * @param {Object} context */ async asideTransitionToggle ({ state, dispatch }) { // store 赋值 state.asideTransition = !state.asideTransition // 持久化 await dispatch('d2admin/db/set', { dbName: 'sys', path: 'menu.asideTransition', value: state.asideTransition, user: true }, { root: true }) }, /** * 持久化数据加载侧边栏设置 * @param {Object} context */ async asideLoad ({ state, dispatch }) { // store 赋值 const menu = await dispatch('d2admin/db/get', { dbName: 'sys', path: 'menu', defaultValue: setting.menu, user: true }, { root: true }) state.asideCollapse = menu.asideCollapse !== undefined ? menu.asideCollapse : setting.menu.asideCollapse state.asideTransition = menu.asideTransition !== undefined ? menu.asideTransition : setting.menu.asideTransition } }, mutations: { /** * @description 设置顶栏菜单 * @param {Object} state state * @param {Array} menu menu setting */ headerSet (state, menu) { // store 赋值 state.header = menu }, /** * @description 设置侧边栏菜单 * @param {Object} state state * @param {Array} menu menu setting */ asideSet (state, menu) { // store 赋值 state.aside = menu } } } ``` 到 /src/store/modules/d2admin/modules/account.js `account.js` 新增一个action updateCache ```javascript updateCache ({ dispatch }, { to = '/' }) { return new Promise((resolve, reject) => { // 设置菜单 dispatch('d2admin/menu/set', {}, { root: true }) // 设置路由 api.ROUTER_CURRENT().then(result => { dispatch('d2admin/router/load', { to: to, focus: true, data: result }, { root: true }) }) resolve() }) } ``` api请求 /src/api/modules/sys.menu.api.js `sys.menu.api.js` ```javascript const baseURL = '/admin' export default ({ request }) => ({ // 菜单请求 MENU_CURRENT (data = {}) { return request({ url: baseURL + '/menu/get/current/menutree', method: 'get' }) }, // 路由请求 ROUTER_CURRENT (data = {}) { return request({ url: baseURL + '/menu/get/current/vuerouter', method: 'get' }) } }) ``` 响应报文 ```json { "code": 0, "msg": "请求成功", "data": [ { "id": 1, "title": "信评中心", "enname": "crManager", "parentId": -1, "icon": "folder-o", "sort": 1, "isEnabled": 1, "children": [ { "id": 2, "title": "信评工作台", "enname": "crWorkbench", "parentId": 1, "icon": "folder-o", "sort": 2, "isEnabled": 1, "children": [ { "id": 3, "title": "信用评级待办", "parentId": 2, "icon": "folder-o", "sort": 3, "isEnabled": 1 } ] }, { "id": 4, "title": "信用评级启动", "parentId": 1, "icon": "folder-o", "isEnabled": 1, "children": [ { "id": 5, "title": "个人评级", "enname": "cr_person_launch", "parentId": 4, "path": "/cr_person_launch", "component": "cr/cr_launch/cr_person_launch/cr_person_launch", "icon": "folder-o", "isEnabled": 1 }, { "id": 6, "title": "企业评级", "enname": "cr_business_launch", "parentId": 4, "path": "/cr_business_launch", "component": "cr/cr_launch/cr_business_launch/cr_business_launch", "icon": "folder-o", "isEnabled": 1 } ] }, { "id": 7, "title": "信用评级查询", "parentId": 1, "icon": "folder-o", "isEnabled": 1 }, { "id": 8, "title": "评级模板管理", "parentId": 1, "icon": "folder-o", "isEnabled": 1 } ] }, { "id": 9, "title": "系统管理", "parentId": -1, "icon": "folder-o", "isEnabled": 1, "children": [ { "id": 10, "title": "用户管理", "enname": "usertable", "parentId": 9, "path": "/usertable", "component": "user/usertable", "icon": "folder-o", "isEnabled": 1 }, { "id": 11, "title": "菜单管理", "enname": "menu", "parentId": 9, "path": "/menu", "component": "menu/menu", "isEnabled": 1 }, { "id": 16, "title": "权限管理", "enname": "role", "parentId": 9, "path": "/role", "component": "role/role", "isEnabled": 1 } ] }, { "id": 12, "title": "演示页面", "parentId": -1, "isEnabled": 1, "children": [ { "id": 13, "title": "页面 1", "enname": "page1", "parentId": 12, "path": "/page1", "component": "demo/page1", "isEnabled": 1 }, { "id": 14, "title": "页面 2", "enname": "page2", "parentId": 12, "path": "/page2", "component": "demo/page2", "isEnabled": 1 }, { "id": 15, "title": "页面 3", "enname": "page3", "parentId": 12, "path": "/page3", "component": "demo/page3", "isEnabled": 1 } ] } ], "type": "success" } ``` # 包管理器 ## npm包管理器 ```shell # 淘宝镜像 # 永久生效 npm config set registry http://registry.npm.taobao.org/ # 查看镜像 npm config get registry # 暂时生效 npm install --registry http://registry.npm.taobao.org/ ``` ### CentOS7安装node js ```shell # 首先下载nodejs安装包 # 解压 注意这不是gz压缩 tar -xvf node-v14.18.1-linux-x64.tar.xz mv node-v14.18.1-linux-x64.tar.xz /usr/node vim /etc/profile # node export NODE_HOME=/usr/node export PATH=$PATH:$NODE_HOME/bin source /etc/profile # 查看node 版本 node -v npm -v # 安装yarn npm install -g yarn # 软连接,防止找不到环境 ln -s "/usr/node/bin/node" "/usr/local/bin/node" ln -s "/usr/node/bin/npm" "/usr/local/bin/npm" ln -s "/usr/node/bin/yarn" "/usr/local/bin/yarn" ``` ## yarn包管理器 ```shell # PowerShell yarn : 无法加载文件 C:\Users\Admin\AppData\Roaming\npm\yarn.ps1,因为在此系统因为在此系统上禁止运行脚本。 # 以管理员方式运行powershell set-ExecutionPolicy RemoteSigned # 查看当前镜像 yarn config get registry # https://registry.yarnpkg.com # 更换镜像 yarn config set registry https://registry.yarnpkg.com # 查看镜像是否成功 yarn config get registry # 全局安装PTE脚手架 yarn global add generator-pte-cli # 安装依赖 yarn # 运行项目 yarn dev # yarn run dev # 部署 # 具体看 package.json yarn deploy yarn build # 移除依赖 yarn remove pte-ui # 安装依赖 yarn add pte-ui@2.1.54 ``` ### 安装node-sass ```shell # 安装gyp npm install -g node-gyp npm config set python python2.7 npm config set msvs_version 2017 yarn ``` ### yarn和npm命令对比 | npm | yarn | 注释 | | ------------------------------- | ---------------------------- | --------------------------------- | | npm init | yarn init | 初始化项目 | | npm install | yarn | 安装全部依赖 | | npm install react --save | yarn add react | 安装某个依赖,保存到dependencies | | npm uninstall react --save | yarn remove react | 移除某个依赖 | | npm install react --save-dev | yarn add react --dev | 安装某依赖,保存到devDependencies | | npm update react --save | yarn upgrade react | 更新某个依赖包 | | npm install react --global | yarn global add react | 全局安装某个依赖 | | npm install --save react axios | yarn add react axios | 同时安装多个依赖包 | | npm install [package]@[version] | yarn add [package]@[version] | 安装指定版本的包 | | npm rebuild | yarn install --force | 重新下载所有包 | # 加密解密 ## jsencrypt ### 安装 ```shel npm install jsencrypt --save-dev ``` 引入 ```javascript import jsencrypt from 'jsencrypt' ```