程序员思维导图、web初学者必备、web前端知识集锦-不断更新中...

写完代码一定要自测,每个场景都要测试到,加油吧,骚年......
说话之前一定要考虑后果,版本问题一定要回答谨慎些,比如这个版本就是明天发版(头疼ing......),一句话引发的血案
1.判断是否是微信浏览器
export function isWechat() {
const ua = window.navigator.userAgent.toLocaleLowerCase()
  return !!ua.match(/MicroMessenger/i)
}
2. 图片压缩网站,很好用的
图片压缩:https://tinyjpg.com/
3.键盘弹起事件处理
/*
键盘弹起处理
ios 键盘弹起,window.innerHeight 不变,body、html 的 clientHeight、offsetHeight 增大,页面整体上移,暂不做特殊处理
android 键盘弹起,window.innerHeight、body、html 的 clientHeight、offsetHeight 均变小,需要将 input 框滚动到可视区
*/
const originHeight = document.documentElement.clientHeight || document.body.clientHeight
window.addEventListener('resize', () => {
const resizeHeight = document.documentElement.clientHeight || document.body.clientHeight
// android 键盘弹起
if (originHeight > resizeHeight) {
// 将元素滚动到可视区域
const activeElement = document.activeElement
const tagName = activeElement.tagName
if (tagName === 'INPUT' || tagName === 'TEXTAREA') {
activeElement.scrollIntoViewIfNeeded()
}
}
}, false)
 4. overflow-y: scroll 和height: calc(100vh - 3.4rem) 引发的血案4小时改bug...
1. 父组件滚动时,只需要添加属性overflow: scroll;height: 100vh;
2. 子组件要滚动时,设置overflow: scroll;后还需要确定它的滚动高度,如maxHeight: 580px等等,反正滚动两个条件高度和设置滚动属性,重复3万篇
3. calc 动态高度 当组件无法撑满屏幕时,可以通过calc,如height: calc(100vh - 3.4rem), 这里的3.4rem是已知减去的高度

5.部署rms引发问题思考...

1. 部署文件不生效,首先想到的问题是部署的文件路径对不对,重复3.1万篇...
2. 有没有/需不需要刷新CDN。
3. 代码是否在有错误,打包是否成功。
4. 第一次生效了,其它时间没有生效,很可能是你的文件路径部署错了,不要部署根目录下,如根目录是/c,要部署在具体文件夹下如/c/项目目录。

6.清除sourcetree远程无用的分支 

解决方法:

1、进入对应目录下,使用  git remote show origin  命令查看本地仓库追踪远程仓库的状态
2、使用  git remote prune origin  清除所有失效的远程分支或根据提示删除特定失效分支
3、重启 SourceTree 即可。
7. function 方法只能点击一次问题
  const itemFunc = function () {
    console.log("点击我")
  }
   如组件里有click方法,{click: itemFunc}, 这样点击可以操作,但问题只能调用一次
 加上.keep=true 就可以解决,功能保持,具体原因待更新...
const itemFunction = function (){console.log("功能保持")}
itemFunction.keep = true

// 组件方法如:
{click:itemFunction }

8. background-repeat: no-repeat; 设置背景时一定要加上这个属性,背景不重复,要不在移动端不同手机会出现怪异的现象

9.grid布局,待更新...

10.单行和多行溢出处理
.container {
width: 300px;
height: 200px;
margin: 20px;
padding: 20px;
border: 1px solid #eee;
font-size: 13px;
color: #555;
}
.c-red {
color: red;
}
p {
background-color: rgba(189, 227, 255, 0.28);
padding: 2px 5px;
}
     
 /*单行*/
      .single {
        width: 300px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        word-break: break-all;
      }
      /*多行*/
      .mutiple {
        display: -webkit-box; /*重点,不能用block等其他,将对象作为弹性伸缩盒子模型显示*/
        -webkit-box-orient: vertical; /*从上到下垂直排列子元素(设置伸缩盒子的子元素排列方式)*/
        -webkit-line-clamp: 4; /*行数,超出三行隐藏且多余的用省略号表示...*/
        line-clamp: 4;
        word-break: break-all;
        overflow: hidden;
        max-width: 100%;
      }

<!-- 单行和多行溢出处理 -->

<div class="container">
<p class="single">
<span class="c-red">单行溢出:</span>《ECMAScript 6 入门教程》是一本开源的 JavaScript 语言教程,
全面介绍 ECMAScript 6 新引入的语法特性。
</p>
<p class="mutiple">
<span class="c-red">多行溢出:</span>《ECMAScript 6 入门教程》是一本开源的 JavaScript 语言教程,
全面介绍 ECMAScript 6 新引入的语法特性。本书覆盖 ES6 与上一个版本 ES5 的所有不同之处,
对涉及的语法知识给予详细介绍,并给出大量简洁易懂的示例代码。
</p>
</div>

11. 解决安卓手机字体不加粗

// 设置优先级 
font-weight: bold !important

12.实现菜单的展开与收起及modal视图

  12.1 展开与收起

 
部分代码如下:
// 1. div 部分
    <nav id="navbar">
      <div class="logo">
        <img src="https://randomuser.me/api/portraits/men/76.jpg" alt="user" />
      </div>
      <ul>
        <li><a href="#">Home</a></li>
        <li><a href="#">Portfolio</a></li>
        <li><a href="#">Blog</a></li>
        <li><a href="#">Contact Me</a></li>
      </ul>
    </nav>
      <!-- 菜单按钮 -->
      <button id="toggle" class="toggle">
        <!-- 样式 -->
        <i class="fa fa-bars fa-2x"></i>
      </button>
// 2. 左侧菜单栏,展示的菜单栏,设置为固定,宽度为200px,默认隐藏起来,设置水平偏移-100%,transform: translateX(-100%);也就是隐藏
  css部分
:root {
  --modal-duration: 1s;
  --primary-color: #30336b;
  --secondary-color: #be2edd;
}
nav {
  background-color: var(--primary-color);
  border-right: 2px solid rgba(200, 200, 200, 0.1);
  color: #fff;
  position: fixed;
  top: 0;
  left: 0;
  width: 200px;
  height: 100%;
  z-index: 100;
  /* 移动-100%,也就是隐藏掉 */
  transform: translateX(-100%);
}
// 重要,这里的css是紧挨着的,不可以有空格,水平向右偏移200px,也就是左侧菜单栏的宽度
body.show-nav {
  /* Width of nav */
  transform: translateX(200px);
}
// 3. 调用js实现dom的单击事件
// 3.1 先找到菜单div
const toggle = document.getElementById('toggle'); // 菜单按钮
const navbar = document.getElementById('navbar'); // navbar
// 3.2 实现单击
function closeNavbar (e) {
  if (document.body.classList.contains('show-nav') &&
  e.target !== toggle &&
  !toggle.contains(e.target) &&
  e.target !== navbar && 
  !navbar.contains(e.target)) {
    document.body.classList.toggle('show-nav');
    document.body.removeEventListener('click', closeNavbar);
  }else if (!document.body.classList.contains('show-nav')) {
    document.body.removeEventListener('click', closeNavbar);
  }
}
toggle.addEventListener('click', () => {
  document.body.classList.toggle('show-nav'); // 可以实现左边菜单关闭与打开
  document.body.addEventListener('click', closeNavbar);
})
View Code

 展开收起

      12.2 modal视图(添加删除css,classList)

13.vue-cli从搭建到优化

https://juejin.cn/post/6844903760917954567#heading-14

14. el-tabel 校验

    // 关键代码如下:
  <el-form :model="form" ref="form" :rules="formRules">
        <el-table :data="sccForm.tableList" border>
          <el-table-column label="测试" width="200" align="center">
            <template slot-scope="scope">
              <el-form-item :prop="'tableList.' + scope.$index + '.test'" :rules="sccFormRule.scc2Pre">
                <input v-model="scope.row.scc2Pre" class="input-card"/>
              </el-form-item>
            </template>
          </el-table-column>
        </el-table>
     </el-form>

// data 
data () {
  return {
    form: {
      tableList: []
    },
    formRules: {test: [{ required: true, message: 'test不能为空', trigger: 'blur' }]}
  }
}
View Code

15. dialog 对话框中滚动

// 内容滚动 ::v-deep vue专用 
::v-deep .pub-dialog-class {
  .el-dialog__body{max-height: 60vh;overflow: auto;}
  // .el-form-item {
  //   margin-bottom: 15px;
  //   input {
  //     width: 180px;
  //     height: 36px;
  //     border: 1px solid #DCDFE6;
  //     color: #7e7878;
  //     transition: border-color .2s cubic-bezier(.645,.045,.355,1);
  //     border-radius: 4px;
  //     outline: none;
  //     padding: 0 10px;
  //   }
  // }
}
this.$nextTick(() => {
  let container = this.$el.querySelector('.el-table__body-wrapper');
  container.scrollTop = container.scrollHeight;
})
View Code

16. 使用swiper3 及swiper时要注意,使用属性loop:true,不能在dom上使用点击事件,点击的话,会导致第一张滑到最后一张时不能点击

 需要在swiper里实现onClick事件

if (this.swiper) {
this.swiper.destroy();
this.swiper = null;
}
this.swiper = new Swiper(this.$refs.swiperDom, {
direction: 'vertical',
speed: 300,
autoplay: 3000,
autoplayDisableOnInteraction: false,
observer: true,
observeParents: true,
onClick: (swiper, event) => {
this.itemClick(this.swiper.realIndex);
},
loop: true
});

// css样式调整

.swiper-pagination-bullet {

    margin: 0 13px;

}
View Code

17. el-upload 自定义上传,部分关键代码

  data () {
    return {
      list:[{name: 'cs1', id: '5'}, {name: 'cs1', id: '24'}],
      selectModule: '', // 选择某列表中一个
      selectModuleName: '', // 下载的名称
      selectModuleUrl: '' // 下载的地址
    }
  }

<div>
  <span>下载模版:</span>
  <el-select v-model="selectModule" @change="handleSelectModule" placeholder="请选择下载模板" style="margin-left: 20px; width: 300px; height: 36px;">
    <el-option v-for="item in list" :key="item.id" :value="item.id" :label="item.name" />
  </el-select>
  <a :href="selectModuleUrl" :download="selectModuleName">下载</a>
</div>

handleSelectModule (val) {
  // 获取模版下载地址
  const params = {
    fileId: val,
    type: 1
  }
  downLoadExcel(params, '下载地址').then(res => {
    var reader = new FileReader()
    reader.readAsText(res.data, 'gbk')
    const _this = this
    reader.onload = function (e) {
      try {
        var result = JSON.parse(reader.result)
        console.log(result)
        _this.$message({
          type: 'error',
          message: '下载模版不存在'
        })
      } catch (err) {
        const url = window.URL.createObjectURL(res.data)
        let proName = ''
        for (let i = 0; i < _this.list.length; i++) {
          if (_this.list[i].proID === val) {
            proName = _this.list[i].proName
            break
          }
        }
        _this.selectModuleUrl = url
        _this.selectModuleName = `${proName}下载模版名称.xls`
      }
    }
  }).catch(error => {
    console.log(error)
  })
},

// 下载方法
import axios from 'axios'

function downLoadExcel (params, url) {
  console.log(params, url)
  return axios({
    baseURL: `${API_ROOT}`, // 下载的基本地址, url是拼接下载地址(后缀), 如 http://www.baidu.com/downUrl
    withCredentials: true,
    crossDomain: true,
    url: url,
    method: 'post',
    responseType: 'blob',
    params: params
  })
}
// 上传
data () {
    return {
      size: null, // 文件大小
      fileInfo: {
        name: '',
        file: undefined
      },
      id: ''
      dialogVisible: false
    }
}
   <input ref="fileUpload" type="file" @change="fileUpload($event)" style="width: 0px; height: 0px;visibility: hidden;"/>
    <span v-if="!(fileInfo.name)" @click="handleCheckFile" class="opItem">请选择上传类型</span>
    <span class="opItem">{{fileInfo.name}}</span>
    <div class="dialog-content">
     <el-select filterable v-model="selectProject" @change="handleSelectModule" placeholder="请选择上传项目" style="margin-left: 20px; width: 300px; height: 36px;">
      <el-option v-for="item in list" :key="item.id" :value="item.id" :label="item.name" />
    </el-select>
      上传:
  handleSelectModule () {
    // 调用下载方法
    如上
  }
  handleCheckFile () {
    this.$refs.fileUpload.click()
  },
  fileUpload (e) {
    // console.log(e.target.files[0])
    // let type = e.target.files[0].name.split('.')[1]
    this.fileInfo.name = e.target.files[0].name
    this.fileInfo.file = e.target.files[0]
    this.size = e.target.files[0].size
    // this.size = bigSize / 1024;
    this.$refs.fileUpload.value = null
  },
  uploadList () {
      if (this.size > 30 * 1024 * 1024) {
        this.$message({
          type: 'error',
          message: '文件不能超过30M'
        })
        return
      }
      this.dialogVisible = false
      uploadFileAsync({ file: this.fileInfo.file, id: this.id, url: '/xxxx/uploadExcel' })
        .then(res => {
         console.log('---成功操作')
        })
        .catch(error => {
          this.fileInfo = {
            name: '',
            file: undefined
          }
          this.$message({
            type: 'error',
            message: error.responseMsg
          })
        })
    },
  function uploadFileAsync (params) {
  const { file, id, url } = params
  var formData = new FormData()
  formData.append('uploadFile', file)
  return axios({
    baseURL: `${API_ROOT}`,
    url: url,
    data: formData,
    timeout: 600000,
    method: 'post',
    headers: {
      'Content-Type': 'multipart/form-data'
    },
    withCredentials: true,
    crossDomain: true,
    params: {
      id: id
    }
  }).then(res => {
    return Promise.resolve(res.data)
  }).catch(error => {
    console.log(error)
    return Promise.reject(new Error({ responseCode: '20089', responseMsg: '请求出错了,请稍后再试' }))
  })

18. encodeURIComponent() 浏览器转码问题要注意,特殊字符如,容易转换失败,传给后端无法解析

19. vue h5 移动端滚动不流畅,不丝滑,可以试试加上下面的css

    overflow: auto;
    -webkit-overflow-scrolling: touch;

20. flex布局设置 ellipsis, css如下

   .item {
      display: flex;
      align-items: center;
      .item-text {
        overflow: hidden;
        flex: 1;
        white-space: nowrap;
        text-overflow: ellipsis;
      }
    }
View Code

21. textarea的哪些坑

   1. 高度自适应,textarea本身是不会自适应的,超过高度会滚动,这里我们就从滚动入手,最好不好用自适应高度

     TODO: 目前撤消文字的话高度没有变还没有解决;

     TODO: 回显时重置textarea的高度还没有解决,比如说已经发布的文字重新编辑时的回显。

  解决方法很简单:就是把它的滚动高度赋值给高度,上源码如下:

// 其实就下面几行代码,是不是很简单
      <div>
        <textarea class="textarea"
          onpropertychange="style.height=scrollHeight+'px';" 
          oninput="style.height = scrollHeight+'px';"></textarea>
      </div>
核心代码就这onpropertychange="style.height=scrollHeight+'px';" oninput="style.height = scrollHeight+'px';"

完整代码:这里为了textarea,走了不少弯路,还用div来实现,不过发现了不少坑,换行的坑还没有埋,所以还是使用原生方法,无坑

  2. maxlength 算字数限制时,超过2个换行符,字数就失效,Vue实现动态显示textarea剩余文字数量,解决办法如下:

<template>
  <div id="app">
    <div class="discussWrap">
      <textarea class="description" @input="descInput" cols="33" rows="8" v-model="des"></textarea>
      <div class="font-count">{{countNum}}/50</div>
    </div>
  </div>
</template>
methods: {
    descInput(){
      if(this.desc.length>50){
        this.desc=this.desc.slice(0, 50)
      }
      this.countNum= this.desc.length
    }
}

需要安装vue,然后导入使用

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title></title>
    <meta name="description" content="">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="">
    <script src="../../node_modules/vue/dist/vue.js"></script>
    <style>
      *{
                margin: 0;
                padding: 0;
            }
      .input:empty::before{
                color:lightgrey;
                content:attr(placeholder);
            }
            .input{
                width: 400px;
        min-height: 40px;
        outline: 0 none;
        border-color: rgba(82, 168, 236, 0.8);
        box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6);
      }
      .textarea {
        resize: none;
        overflow-y: hidden;
        width: 100px;
        min-height:70px;
      }
    </style>
  </head>
  <body>
    <!-- contenteditable 换行问题还没有解决
    坑1: 换行
    坑2: 粘贴有格式的东西,需要去格式,例子中已经解决 -->
    <!-- <div id="app">
      <div>顶面</div>
      <div>
        <div class="input" contenteditable placeholder="请输入文字" @keyup="editnameSet($event)"></div>
      </div>
      <div>底面</div>
      <textarea v-model="app" class="input"></textarea>
    </div> -->
    <!-- 单击输入框发现也会触发onpropertychange,输入一个值同样也会触发这个事件,这就证明了,只要有属性的值被修改就会触发该事件。
    oninput 事件在用户输入时触发。-->
    <div id="app">
      <div>顶部</div>
      <div>
        <textarea class="textarea"
          onpropertychange="style.height=scrollHeight+'px';" 
          oninput="style.height = scrollHeight+'px';"></textarea>
      </div>
      <div>底部</div>
    </div>
    <script>
       //兼容处理,统一换行时的元素渲染
      //  document.execCommand("defaultParagraphSeparator", false, "div");  
      new Vue ({
        el: '#app',
        data () {
          return {
            app: '2233'
          }
        },
        mounted () {
          // const input = document.getElementsByClassName('input');
          // if (input) {
            // console.log('----------input', input[0].innerHTML = this.app);
            // input.target.innerText = this.app;
          // }
          // const areas = document.getElementById('textarea');
          // areas.addEventListener('input', function() {
          //     this.style.height = this.scrollHeight+'px'; 
          // }, false);
        },
        watch: {
          app (newval) {
            const textarea = document.getElementsByClassName('textarea')[0];
            console.log('----te', textarea.style);
            // textarea.style.height = 'auto';// 1. 让 textarea 的高度恢复默认
            // textarea.style.height = textarea.scrollHeight + 'px';// 2. textarea.scrollHeight 表示 *textarea* 内容的实际高度
          }
        },
        methods: {
          editnameSet (set) {
             var re=/<[^>]*>/g;    //清空标签的正则
             const str = set.target.innerText.replace(re,"")
             set.target.innerText = str;
            console.log();
          },
          changeContent (val) {
            console.log(val);
          }
        }
      })
    </script>
  </body>
</html>
View Code

22.backImage和image的使用遇到的问题

1.background-image 使用时只显示颜色没有显示图片,怎么回事,你没有加下面属性,完整版
     height: 184px; 
      background-image: url('../../assets/img/announcement/announcement-template-ybtz.png');
      background-position: top left; // 位置
      background-size: 100%;
      background-repeat: no-repeat; // 不重复
2. image加载图片方法
第一种: 固定图片src直接添加地址    <img class="nd-img nd-img00"  src="../assets/img/no_task_img00.png" alt="">
第二种: 动态添加图片,这里用到require, item的遍历数组的每一页取的图片名称
  <img :src="require(`../assets/img/approve_ing${item.name}.png`)">
但require 的优化方便,快捷;缺点:会把导入的图片加载成base64,占用空间,加载图片比较慢
3. background-image加载图片方法
    <div class="template-img" :class="handleTemplateBgImage(item)">
     </div>
methods: {
    handleTemplateBgImage (item) {
      let tempClass = `bg-img-${item.imgName}`;
      if (parseInt(this.templateId) === item.templateId) {
        tempClass = `${tempClass} active`;
      }
      return tempClass;
    },
}
css部分:
.bg-img-template-ybtz {
  background-image: url(~@/assets/img/announcement/ybtz.png) !important;
}
.bg-img-template-xb {
  background-image: url(~@/assets/img/announcement/xb.png) !important;
}
.bg-img-template-yjbb {
  background-image: url(~@/assets/img/announcement/yjbb.png) !important;
}
.bg-img-template-jctg {
  background-image: url(~@/assets/img/announcement/jctg.png) !important;
}
    .template-img {
      width: auto;
      height: 180px;
      margin-top: 24px;
      margin-bottom: 32px;
      border: 2px solid #ffffff;
      border-radius: 12px;
      background-position: top left;
      background-size: 100%;
      background-repeat: no-repeat;
    }

23. filter的使用

filter的使用
1. 创建filter
创建文件夹filters,创建index.js
const SelectTemplate = {
  TEMPLATE_LIST: [
    { text: '模版一', imgName: 'xb', templateId: 2 },
    { text: '模版二', imgName: 'yjbb', templateId: 3 },
    { text: '模版三', imgName: 'template-jctg', templateId: 4 },
    { text: '模版四', imgName: 'template-ybtz', templateId: 1 }
  ]
};
export default Template;
或
import { templateBg } from '../utils/enum';
const filters = {
  // 选择模板背景
  filterTemplateBg: value => {
    return `swiper-slide-${templateBg[parseInt(value)]}`;
  }
};
export default filters;
index.js文件
import Template from '../utils/Template';
const tempList = SelectTemplate.TEMPLATE_LIST;
export const filterTemplateLabel = value => {
  const obj = tempList.filter(item => {
    return item.templateId === parseInt(value);
  });
  if (obj && obj.length) {
    return obj[0].text;
  } else {
    return tempList[tempList.length - 1].text;
  }
};
export const filterTemplateBgColor = value => {
  const obj = tempList.filter(item => {
    return item.templateId === parseInt(value);
  });
  let bgColor = '';
  if (obj && obj.length) {
    bgColor = obj[0].imgName;
  } else {
    bgColor = tempList[tempList.length - 1].imgName;
  }
  return `bg-${bgColor}`;
};
2. 全局引用
main.js中引用
import * as filters from '../platform/filters';
Object.keys(filters).forEach(key => {
  Vue.filter(key, filters[key]);
});
3. 使用
<div class="input-value">{{ currentTemplateId | filterTemplateLabel }}</div>
<div class="announcement-form" :class="currentTemplateId | filterTemplateBgColor"></div>

24. el-form 与form 等表单校验

25. 千分位处理函数

function formatNumber(num) { 
  if (isNaN(num)) { 
    throw new TypeError("num is not a number"); 
  } 
  
  return ("" + num).replace(/(\d{1,3})(?=(\d{3})+(?:$|\.))/g, "$1,");  
} 

26. 本地后管访问测试环境数据,使用代理代码如下:

  vue.config.js

devServer: {
    proxy: {
      // proxy all requests starting with /api to jsonplaceholder
      '/api': {
        target: 'http://xxx.com.cn/', // 代理接口,这个是测试环境接口
        changeOrigin: true,
        logLevel: 'debug',
        pathRewrite: {
          '^/api': '' // 路径中字符替换
        }
      }
    }
  }

  本地develop设置

 

27. js forEach循环调用异步方法,如何实现同步,参考文章:https://blog.csdn.net/alex_programmer/article/details/104383843

array.forEach(async (item, index) => {
  const res = await requestUrl({item.udmp})
  if (res && res.responseCode === '000000') {
      url = (res.data && res.data.url) || ''
   }
  ... 逻辑代码 push(url)
})

  

28.resolve拼接路径,一般用于链接跳转或读取生产或测试环境的图片

router.resolve() 的解释和用法
const resolved: {
  location: Location;
  route: Route;
  href: string;
} = router.resolve(location, current?, append?)
解析目标位置 (格式和 <router-link> 的 to prop 一样)。

current 是当前默认的路由 (通常你不需要改变它)
append 允许你在 current 路由上附加路径 (如同 router-link)
上面的内容为官网中的说明,可以得知其作用是:返回一个完整的路径信息。
location 参数为必填项;current 和 append 为可选参数,暂时没有遇到过相关用法。
 应用场景
const routeUrl = this.$router.resolve({
        name: 'ListDetail',
        query: {
          type: '001',
          id: id
        }
      })
// location.origin 代表ip地址如http:www.baidu.com,location.pathname相当于具体的子页面如zhidao,/zhidao***,routeUrl.href具体的列表详情信息
      let url = `${location.origin}${location.pathname}${routeUrl.href}`
  windows.open(url, '_blank')

29.伪元素动态获取内容,待更新...

30. lang="scss"  node-sass,sass-loader的安装

  安装失败可能是最新版本问题,可以安装指定版本

  "sass-loader": "^7.3.1",
  npm install sass-loader@7.3.1 --save -dev
  npm install node-sass@7.0.1 --save -dev
  如果安装node-sass失败可以通过cnpm 来安装
 cnpm install node-sass --save 

  

 

posted @ 2021-03-28 15:53  TheYouth  阅读(99)  评论(0编辑  收藏  举报