Skip to content
索引

vue2语法

项目创建

@vue/cli

@vue/cli 是 vue 官方的脚手架,可以使用其快速创建一个 vue 项目的模板

使用@vue/cli 可以安装 vue2 和 vue3 的模板,@vue/cli基于 webpack 打包工具

安装

bash
# 安装全局脚手架命令
npm i -g @vue/cli
# 创建项目,选择相应模板
vue create vue-project-name
# 进入项目目录
cd vue-project-name
# 使用vscode打开当前目录的项目
code ./
# npm运行项目
npm run serve
# yarn运行项目
yarn serve
# 安装全局脚手架命令
npm i -g @vue/cli
# 创建项目,选择相应模板
vue create vue-project-name
# 进入项目目录
cd vue-project-name
# 使用vscode打开当前目录的项目
code ./
# npm运行项目
npm run serve
# yarn运行项目
yarn serve

删除创建的预设

删除C:\Users\用户名下的.vuerc

vue.config.js

@vue/cli使用node读取该配置文件,从而对webpack进行设置

js
const FileManagerPlugin = require("filemanager-webpack-plugin") // 自动压缩文件
module.exports = {
  publicPath: "/",   //基本路径
  outputDir: "dist", // 输出文件目录
  assetsDir: "./static", // 静态资源输出目录
  lintOnSave: true,
  configureWebpack: {
    output: {
      filename: `[name].1.${Timestamp}.js`,
      chunkFilename: `[name].1.${Timestamp}.js`
    },1
    plugins: [
      // 压缩生成zip文件
      // new FileManagerPlugin({
      //   events: {
      //     onEnd: {
      //       archive: [{ source: "./dist", destination: "./dist.zip" }]
      //     }
      //   }
      // })
    ]
  },
  productionSourceMap: false, // 生产环境是否生成sourceMap文件
  // css相关配置
  css: {
    extract: true,  // 是否将组件中的CSS提取至独立的CSS文件中,基于ExtractTextPlugin
    sourceMap: false,   // 是否开启CSS source maps
    loaderOptions: {
      postcss: {
        plugins: [
          require("postcss-plugin-px2rem")({
            // 128.4 63.9
            // rootValue:128.4,      // 新版本的是这个值
            // mediaQuery: false, //(布尔值)允许在媒体查询中转换px。
            // minPixelValue: 3 //设置要替换的最小像素值(3px会被转rem)。 默认 0
          })
        ]
      }
    }
  },
  // webpack-dev-server相关配置
  devServer: {
    open: false, // 在devServer启动且第一次构建完成时,自动用系统的默认浏览器去打开项目
    host: "100.100.2.217", // 开发服务器ip
    port: 8080, // 开发服务器端口
    hot: false, // 置是否启用模块的热替换功能,devServer的默认行为是在发现源代码被变更后,通过自动刷新整个页面来做到事实预览,开启hot后,将在不刷新整个页面的情况下通过新模块替换老模块来做到实时预览
    https: false, // 是否使用https
    hotOnly: false, // hot 和 hotOnly 的区别是在某些模块不支持热更新的情况下,前者会自动刷新页面,后者不会刷新页面,而是在控制台输出热更新失败
    // 设置代理
    proxy: {
      "/api": {
        target: "http://100.100.2.153:6969",
        secure: false, //false为http访问,true为https访问
        changeOrigin: true,
        rewrite: path => path.replace(/^\/api/, "")
      }
    }
  }
}
const FileManagerPlugin = require("filemanager-webpack-plugin") // 自动压缩文件
module.exports = {
  publicPath: "/",   //基本路径
  outputDir: "dist", // 输出文件目录
  assetsDir: "./static", // 静态资源输出目录
  lintOnSave: true,
  configureWebpack: {
    output: {
      filename: `[name].1.${Timestamp}.js`,
      chunkFilename: `[name].1.${Timestamp}.js`
    },1
    plugins: [
      // 压缩生成zip文件
      // new FileManagerPlugin({
      //   events: {
      //     onEnd: {
      //       archive: [{ source: "./dist", destination: "./dist.zip" }]
      //     }
      //   }
      // })
    ]
  },
  productionSourceMap: false, // 生产环境是否生成sourceMap文件
  // css相关配置
  css: {
    extract: true,  // 是否将组件中的CSS提取至独立的CSS文件中,基于ExtractTextPlugin
    sourceMap: false,   // 是否开启CSS source maps
    loaderOptions: {
      postcss: {
        plugins: [
          require("postcss-plugin-px2rem")({
            // 128.4 63.9
            // rootValue:128.4,      // 新版本的是这个值
            // mediaQuery: false, //(布尔值)允许在媒体查询中转换px。
            // minPixelValue: 3 //设置要替换的最小像素值(3px会被转rem)。 默认 0
          })
        ]
      }
    }
  },
  // webpack-dev-server相关配置
  devServer: {
    open: false, // 在devServer启动且第一次构建完成时,自动用系统的默认浏览器去打开项目
    host: "100.100.2.217", // 开发服务器ip
    port: 8080, // 开发服务器端口
    hot: false, // 置是否启用模块的热替换功能,devServer的默认行为是在发现源代码被变更后,通过自动刷新整个页面来做到事实预览,开启hot后,将在不刷新整个页面的情况下通过新模块替换老模块来做到实时预览
    https: false, // 是否使用https
    hotOnly: false, // hot 和 hotOnly 的区别是在某些模块不支持热更新的情况下,前者会自动刷新页面,后者不会刷新页面,而是在控制台输出热更新失败
    // 设置代理
    proxy: {
      "/api": {
        target: "http://100.100.2.153:6969",
        secure: false, //false为http访问,true为https访问
        changeOrigin: true,
        rewrite: path => path.replace(/^\/api/, "")
      }
    }
  }
}

vue3 不支持 ie11

搭建兼容ie的vue2模板

json
{
  "name": "vue2-template",
  "version": "0.0.0",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview --port 4173"
  },
  "dependencies": {
    "axios": "^0.27.2",
    "element-ui": "^2.15.10",
    "vue": "^2.7.7",
    "vue-router": "^3.5.4",
    "vuex": "^3.6.2"
  },
  "devDependencies": {
    "@vitejs/plugin-legacy": "^2.0.0",
    "@vitejs/plugin-vue2": "^1.1.2",
    "terser": "^5.14.2",
    "unplugin-auto-import": "^0.11.2",
    "unplugin-vue-components": "^0.22.7",
    "vite": "^3.0.2",
    "sass": "^1.32.8",
    "sass-loader": "^7.1.0"
  }
}
{
  "name": "vue2-template",
  "version": "0.0.0",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview --port 4173"
  },
  "dependencies": {
    "axios": "^0.27.2",
    "element-ui": "^2.15.10",
    "vue": "^2.7.7",
    "vue-router": "^3.5.4",
    "vuex": "^3.6.2"
  },
  "devDependencies": {
    "@vitejs/plugin-legacy": "^2.0.0",
    "@vitejs/plugin-vue2": "^1.1.2",
    "terser": "^5.14.2",
    "unplugin-auto-import": "^0.11.2",
    "unplugin-vue-components": "^0.22.7",
    "vite": "^3.0.2",
    "sass": "^1.32.8",
    "sass-loader": "^7.1.0"
  }
}

watch

监听vue实例上数据的变动

监听对象

deep属性设为true,修改监听对象中的任何一个属性,都会执行监听的方法

js
watch: {
   queryData: {
     handler() {
      ...
     },
     deep: true
   }
}
watch: {
   queryData: {
     handler() {
      ...
     },
     deep: true
   }
}

监听对象具体属性

js
 watch: {
    "obj.key": {
      handler(val) {
       ...
      },
      deep: true
    }
  }
 watch: {
    "obj.key": {
      handler(val) {
       ...
      },
      deep: true
    }
  }

或者

js
computed: {
    getName() {
    	return this.search.name
    }
}
watch: {
     getName: {
         handler() {
            ...
         }
     }
}
computed: {
    getName() {
    	return this.search.name
    }
}
watch: {
     getName: {
         handler() {
            ...
         }
     }
}

immediate: true

immediate表示初始时就执行

js
 watch: {
    "obj.key": {
      handler(val) {
       ...
      },
      deep: true,
      immediate: true
    }
  }
 watch: {
    "obj.key": {
      handler(val) {
       ...
      },
      deep: true,
      immediate: true
    }
  }

监听多个props

搭配computed实现同时监听多个props

js
 watch: {
    changeData() {
      ...
    }
  },
  computed: {
    changeData() {
      const { id, content } = this.item
      return {
        id,
        content
      }
    }
  }
 watch: {
    changeData() {
      ...
    }
  },
  computed: {
    changeData() {
      const { id, content } = this.item
      return {
        id,
        content
      }
    }
  }

style结合computed

vue
<div class="login-image"  :style="bgStyle">
<div class="login-image"  :style="bgStyle">
js
 computed: {
    bgStyle() {
      let img = this.img
      return {
       background: `url(${img})`,
       backgroundColor: "#e4e9ef",
       backgroundSize: "auto 100%"
      }
    }
  },
 computed: {
    bgStyle() {
      let img = this.img
      return {
       background: `url(${img})`,
       backgroundColor: "#e4e9ef",
       backgroundSize: "auto 100%"
      }
    }
  },

上传文件

js
detail(demo) {
      this.$refs.ruleForm
        .validate(valid => {
          if (valid) {
            if (demo == "save") {
              this.$refs.btn.loading1 = true
            } else {
              this.$refs.btn.loading2 = true
            }
            // 调用保存的接口,并关闭弹框
            let dataObj = XEUtils.clone(this.formData, true)
            delete dataObj.att1
            delete dataObj.att2
            delete dataObj.att3
            const formData = new FormData()
            formData.append("file1", this.fileList[0])
            formData.append("file2", this.fileList[1])
            formData.append("file3", this.fileList[2])
            formData.append("type", this.type)
            formData.append("demo", demo)
            formData.append("data", JSON.stringify(dataObj))
            axios({
              url: window.BASE_URL + "/jjmx/updateJzcsDataByForm",
              method: "post",
              headers: {
                "Content-Type": "multipart/form-data",
                authToken: sessionStorage.getItem("token")
              },
              data: formData
            }).then(res => {
              if (res && res.data && res.data.code == 0) {
                this.$message.success("操作成功")
                this.$emit("getNowTableData")
                this.$emit("close")
              } else if (res && res.data && res.data.code != 0) {
                this.$message.error("操作失败")
              }
            })
          }
        })
        .finally(() => {
          if (demo == "save") {
            this.$refs.btn.loading1 = false
          } else {
            this.$refs.btn.loading2 = false
          }
        })
    },
detail(demo) {
      this.$refs.ruleForm
        .validate(valid => {
          if (valid) {
            if (demo == "save") {
              this.$refs.btn.loading1 = true
            } else {
              this.$refs.btn.loading2 = true
            }
            // 调用保存的接口,并关闭弹框
            let dataObj = XEUtils.clone(this.formData, true)
            delete dataObj.att1
            delete dataObj.att2
            delete dataObj.att3
            const formData = new FormData()
            formData.append("file1", this.fileList[0])
            formData.append("file2", this.fileList[1])
            formData.append("file3", this.fileList[2])
            formData.append("type", this.type)
            formData.append("demo", demo)
            formData.append("data", JSON.stringify(dataObj))
            axios({
              url: window.BASE_URL + "/jjmx/updateJzcsDataByForm",
              method: "post",
              headers: {
                "Content-Type": "multipart/form-data",
                authToken: sessionStorage.getItem("token")
              },
              data: formData
            }).then(res => {
              if (res && res.data && res.data.code == 0) {
                this.$message.success("操作成功")
                this.$emit("getNowTableData")
                this.$emit("close")
              } else if (res && res.data && res.data.code != 0) {
                this.$message.error("操作失败")
              }
            })
          }
        })
        .finally(() => {
          if (demo == "save") {
            this.$refs.btn.loading1 = false
          } else {
            this.$refs.btn.loading2 = false
          }
        })
    },

获取祖先

vue2

js
  data() {
    return {
      isTreeRoot: true
    }
  },
  mounted() {
    // 因为是递归组件,获取最上层的组件,才能正常使用$emit
    let parent = this.$parent
    while (parent && !parent.isTreeRoot) {
      parent = parent.$parent
    }
    this.tree = parent
  },
  data() {
    return {
      isTreeRoot: true
    }
  },
  mounted() {
    // 因为是递归组件,获取最上层的组件,才能正常使用$emit
    let parent = this.$parent
    while (parent && !parent.isTreeRoot) {
      parent = parent.$parent
    }
    this.tree = parent
  },

vue3

js
let currentCpn = getCurrentInstance();
let parent = currentCpn.parent;
let currentCpn = getCurrentInstance();
let parent = currentCpn.parent;

el-tree设置默认选中第一个子元素

js
// 递归获取第一个子元素
function getFirstChild(data) {
  if (data[0].children.length) {
  return getFirstChild(data[0].children)
  } else {
   return data[0]
    }
  }
this.$refs.innerTree.setNodeById(getFirstChild(res.data), true)
this.currentNode = getFirstChild(res.data)
// 递归获取第一个子元素
function getFirstChild(data) {
  if (data[0].children.length) {
  return getFirstChild(data[0].children)
  } else {
   return data[0]
    }
  }
this.$refs.innerTree.setNodeById(getFirstChild(res.data), true)
this.currentNode = getFirstChild(res.data)

Vue2中的语法糖.sync(较低版本)

语法

.sync是一种语法糖 <div :title.sync="visible" ></div>

它等同于下方两者的缩写

<div :title="visible" @input="visible = $event" ></div>

所以子组件想要更新值,这样写this.$emit('input', newValue)

vue3中的语法糖v-model

语法

v-model也是一种语法糖 <div v-model="visible"></div>

它等同于下方两者的缩写

<div v-model:modelValue="visible" @updata:modelValue="visible = $event"></div>

所以子组件想要更新值,这样写this.$emit('updata:modelValue', newValue)

有参数

<div v-model:title="TEXT" ></div> 等同于:<div :title="TEXT" @update:title="TEXT= $event" ></div>

递归组件

js
 data () {
    return {
      root: "",
      isRoot: true,
    }
  },  
mounted () {
    // 因为是递归组件,获取最上层的组件,才能正常使用$emit
    // let root = this.menuLevel === 1 ? this : this.$parent
    // while (root && root.menuLevel !== 1) {
    //   // console.log(root.menuLevel);
    //   root = root.$parent
    // }
    // this.root = root
  },
 data () {
    return {
      root: "",
      isRoot: true,
    }
  },  
mounted () {
    // 因为是递归组件,获取最上层的组件,才能正常使用$emit
    // let root = this.menuLevel === 1 ? this : this.$parent
    // while (root && root.menuLevel !== 1) {
    //   // console.log(root.menuLevel);
    //   root = root.$parent
    // }
    // this.root = root
  },

$set

Vue没有检测到data中数组和对象的变化,因此也不会触发视图更新,手动设置

js
this.$set(tabledata, index, temp);
this.$set(tabledata, index, temp);

Released under the MIT License.