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
- 想要支持 ie11 请使用 vue2
- 官方说明
搭建兼容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);