title: Vue基础教程
date: 2022-01-26 21:09:30
tags: [前端框架,Vue]
categories: 前 端
cover:
Vue基础入门
基础知识:
- HTML+JavaScript+CSS
- Node环境和npm(依赖管理 )
- webpack(可选)
官方文档:
- 学习任何框架,最好的教程就是官方文档,但是官方文档往往是英文的,可能会劝退:( 建议提升英文:)
- 初学者更适合视频学习,等有一定能力便可以向文档进发,因为更加详细:)
DOM是什么?
Document Object Model,简称DOM,中文叫做“文档对象模型”
粗略理解就是:
DOM提供了对文档的结构化表述。从HTML或者xml程序中,对其结构进行访问,以及修改文档的结构、样式和内容,也就是可以对文档结构实现读写功能。(web页面与其源码都被称作是文档)
DOM 的实现
要想实现将js代码中的数据呈现到HTML页面上用DOM实现:
要先获取document/DOM,再获取节点,然后再去操作这个DOM节点(也就是在HTML中进行一系列的操作)。而使用Vue可以直接在html程序中绑定数据,当我们改变js中的数据时,就可以直接在页面上呈现出来
Vue相比于DOM的优点
要想实现将js代码中的数据呈现到HTML页面上,采用Vue可以让这个过程简化许多。
先创建Vue实例:
//创建VUE实例
new Vue({el:"#app", //选择器data:{message:"我喜欢你"
}
})
然后将此实例和HTML中的
<div id="app"><h1>{{meaasge}}</h1> <!-- 双花括号是表达式的意思 -->
</div>
所以,以后我们要在HTML里面用js的数据,就直接写相应的数据名称就可以了,让数据和页面形成一个绑定,我们只要操作数据,页面自己就会跟着变化。
入门知识点
-
文本:双花括号
-
属性:v-bind:
可省略,只写冒号:
-
事件:v-on:
可省略,只写@
注:如果要在函数里面使用Vue中的数据,可以使用this来访问
举例:
<div id="app"><h1>message</h1><img v-bind:src="url"></img> <img :src="url"></img> <button v-on:click=""></button><button @click=""></button>
</div><script>
new Vue({el:"#app", <!-- el为元素选择器的意思-->data:{message="我喜欢你",url="inmages/1.jpg"},methods:{sayLoveYou(){alert("Love you!")}//Vue里的函数集合:methods,包含多个函数//数据集合:data,包含多个变量数据}
})
</script>
小练习:做一个翻页按钮
<body><div id="app"><button @click="sub">-</button><span>{{ number }}</span><button @click="add">+</button></div><script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script><script>new Vue({el:"#app",data:{number:0,},methods: {add(){this.number=this.number+1;},sub(){if(this.number==0){alert("不可以小于零")}elsethis.number--}}})</script>
</body>
</html>
效果:
创建Vue项目
配置开发环境
使用Node.js环境开发,
- cmd安装vue/cli
- 创建项目hello,建议在对应的目录下创建
- 启动服务器
命令:
npm install -g @vue/cli
vue create hello
cd hello
npm run serve
组件化开发概述
什么是组件化呢?
就是我们在html中进经常要用到标签,但是总有我们需要的标签HTML提供不了,所以,组件化开发就是,我们开发的.vue文件(又叫vue组件)作为html中的标签来使用。
例如我们可以开发.vue登录组件或者.vue轮播图组件然后插入到HTML中
优点:简洁与复用
项目结构概述
- 后缀.vue是我们上文中提到的组件,
- main.js是主文件,用于对应id与对应的组件(App.vue)
- components意为组件,一般我们自己开发的,也就是自定义的组件就放在这个目录下
剩余的一些为配置文件,
在这个vue中,我们可以写html、JavaScript、CSS代码,分别对应的是、、
例如:
<template>
<!-- html代码 --><div id="app"><h1>I lOVE You</h1><img alt="Vue logo" src="./assets/friend_404.gif"><h1>{{message}}</h1></div>
</template><script>
// js代码、vue代码
export default { //首先,VUE中的js一定要用export来暴露自己
//其次在以vue为后缀的文件中vue表达数据的书写方式跟在以html为后缀的文件中vue的写法不一样data(){return{message: "Hello world",}}}
</script><style>
/* css代码 */
</style>
引入vue.js文件与Node环境下书写格式的区别
-
引入vue.js:
data:{message:"我喜欢你!" }
-
Node环境下:
data(){return{message: "Hello world",} }
模板语法
指令
v-开头的
条件判断类:
- v-if
- v-show
v-if与v-show的异同点:
-
同:
都可以隐藏或者显示元素(true:显示、false:不显示)
-
异:
if不渲染DOM,如果if为false,在浏览器中不显示
show渲染DOM,如果show都为false,在浏览器中将元素设置为display:one
显示列表与制表类:
v-for
这个for啊,极有可能是遍历,循环的意思
利用v-for指令显示列表
<template>
<!-- html代码 --><div id="app"> <ul><li v-for="(fruit,index) of fruits" :key="index"><p>水果名称:{{fruit}}</p> <p>水果序号:{{index}}</p> <p>水果名称和序号:{{fruit}}序号为{{index}}</p></li></ul></div>
</template><script>
// js代码、vue代码
export default { //首先,VUE中的js一定要用export来暴露自己
//其次在vue中的js代码中的书写方式跟在html中的vue的写法不一样data(){return{fruits:["苹果","芒果","香蕉","原梦"]}}
}
</script>
显示结果:
可以看出就像是一个遍历呢,
一长串如何记住呢?
v-for="(fruit,index) of fruits" :key="index"元素索引属于集合,key的值为索引,然后将这个元素放在{{}}中
利用v-for制表
<template>
<!-- html代码 --><div><table><!-- 将studens显示在表格里 --><thead><th>序号</th><th>姓名</th><th>年龄</th></thead><tbody><!-- <tr>{{v.n}}</tr> --><tr v-for="(v,i) of students" :key="i"><td>{{i + 1}}</td><td>{{v.name }}</td><td>{{v.age}}</td></tr><!-- <tr v-for="(v,i) of students" :key="i">{{v.age}}</tr> --></tbody></table></div>
</template><script>
// js代码、vue代码export default { //首先,VUE中的js一定要用export来暴露自己//其次在vue中的js代码中的书写方式跟在html中的vue的写法不一样components:{Hello,MenuList},data(){return{students:[{name:"张三 ",age:13},{name:"罗翔 ",age:12},{name:"John ",age:18}]}}}
</script><style>
/* css代码 */
</style>
演示效果:
组件嵌套
组件A想要用组件B 的功能,然后需要把组件B嵌套在A中。
三步走:命名、注册、传值
组件命名
B组件命名要首字母大写(小写可能会很HTML标签冲突,不建议这样写),大驼峰式,后缀.vue
注册组件
在B组件中暴露自己,在A组件中引入B组件
import B from "./components/B.vue";
在A中注册组件B,需要在A中写
components:{B:B
}
最后就是将B组价作为A组件的标签,放入A中:
<B>
</B>
组件传值
父子级的概念是,A组件如果包含B组件标签,则称A是B 的父级。
父级向子级传递数据
格式是属性传递(所以用双花括号来表达数据,用:来绑定标签)
首先需要在父级中单向引入子级
然后需要在子级中加入props属性
props是个字符串数组,里面的值为父级传过来的属性名
App.vue为父级
Child.vue为子级
<template>
<!-- html代码 --><div><h1>I lOVE You</h1><Child :msg="message"></Child><Child :mag="message1"></Child></div>
</template><script>import Child from "./components/Child.vue"
export default {components:{Child},data(){return{message:"这里是Vue的数据,我要传到Child组件中,也就是父传子",message1:"我是Vue的二号数据"}}}
</script><style>
/* css代码 */
</style>
<!--==============上面为App.vue=================下面为Child.vue====================--><template>
<div><h1>{{msg}} {{mag}}</h1></div>
</template><script>
export default {props: ["msg","mag"], //props是一个数组的字符串,值为传过来的属性名msgdata(){return{}}
}
</script>
效果图:
子级向父级传递数据
格式是事件传递(@来绑定标签)
比如说我现在想写一个功能,一个子级的按钮button,点击它的时候,把子级的数据传递给父级,然后父级的数据变成子级的一个数据。
先在父级中定义一个自定义事件,然后在子级定义一个按钮,然后绑定点击按钮(@click)发生的方法,在子级中定义这个方法,然后在这个方法中调用方法
this.$emit("toParent", this.msg);
其中
//$emit方法可以触发父级(App.vue)的自定义事件,也就是进行了绑定,向自定义事件toParent传递数据
//$emit方法需要两个参数,1、要绑定的父级中的自定义事件,2、所要传递是数据
//可以这样理解,因为我在App中的Child标签中自定义了事件toParent
//然后我又在Child中的调用了方法this.$emit,所以App就通过Chlid联系起来了
然后,分别在子级,父级中定义变量,用来存放数据(一般都充当容器的作用),子级的变量用来存放要给父级传递的数据,父级的变量用来接收子级传来的数据。
<template><div><div>我是父组件</div><div>我即将接收第二组件传值是:{{child2Msg}}</div><div><div><Child @toParent="getMag" /></div></div></div>
</template><script>
import Child from "./components/Child.vue";export default {components: {Child},data() {return {child2Msg: ""};},methods: {getMag(msg) {this.child2Msg = msg;}}
};
</script><!--==============上面为App.vue=================下面为Child.vue====================--><template><div><div>我是第二个子组件</div><div>我要发送给父组件的值:{{msg}}</div><button @click="toParent">向父组件发送信息</button></div>
</template><script>
export default {data() {return {msg: "我是第二组件,我要给父组件传值",};},methods: {toParent() {this.$emit("toParent", this.msg);}}
};
</script>
效果图:
点击前
点击后
一个父传子,子传父的综合例子:
-
分析过程:
首先我们创建三个组件App.vue、Carts.vue、Counter.vue,然后
-
代码:
<template><div><Carts></Carts></div> </template><script> import Carts from "./components/Carts.vue"export default {components:{Carts},data(){return{msg:""}} } </script> <!--==============上面为App.vue=================下面为Carts.vue====================--><template><div><h1>购物车</h1><ul><li v-for="(v,i) of cars" :key="i">{{v.name}} 单价:{{v.price}} <Counter :qu="v.qu":index="i"@sub="sub"@add="add"></Counter></li></ul></div> </template><script> import Counter from "./Counter.vue" export default {components:{Counter},data(){return{qu:0,cars:[{name:"兰博基尼",price:10000,qu:0},{name:"宝马",price:2000,qu:0},{name:"奔驰",price:4000,qu:0},{name:"特斯拉",price:5000,qu:0},]}},methods:{sub(index){if(this.cars[index].qu==0){alert("数量不可为0哦!")}else{this.cars[index].qu--;}},add(index){this.cars[index].qu++;}} } </script><!--============================下面为Counter.vue===============================--><template><span><button @click="sub">-</button><span>{{qu}}</span><button @click="add">+</button></span> </template><script> export default {props:["qu","index"],data(){return{}},methods:{sub(){this.$emit("sub",this.index);},add(){this.$emit("add",this.index);}} } </script><style></style>
效果图:
总结:
非子级之间传递数据
需要定义一个.js文件,里面存放有两个子级文件都需要操作的全局数据与调用的方法,然后在两个子级文件中分别引入这个.js文件。需要注意的是,如何在两个子级文件中表示对js文件中数据与方法的使用。
<template><div><Brother></Brother><Sister></Sister></div>
</template><script>import Brother from "./components/Brother"
import Sister from "./components/Sister"export default {components:{Carts,Brother, Sister},data(){return{}}
};
</script>
<!--==============上面为App.vue===============下面为Brother.vue====================-->
<template>
<div><h1>brother <button @click="changeData">改变数据</button></h1><p>{{bro.message}}</p>
</div>
</template><script>
import store from "../store.js"export default{data(){return{bro:store.state}},methods:{changeData(){store.setStateMessage("brother data")}}
}
</script><style>
</style>
<!--============================下面为Sister.vue===============================-->
<template>
<div>
<h1>sister</h1>
<p>{{sis.message}}</p>
</div>
</template><script>
import store from "../store.js"export default{data(){return{sis:store.state}}}
</script><style>
</style>
<!--============================下面为store.js===============================-->
export default {state:{message:"Hello Vue"},setStateMessage(str){this.state.message = str;}
}
在Brother中定义变量bro,然后将js文件中的数据赋值给它,使用时使用bro.message,因为在store.js中已经定义了message,Sister中同理。
在Brother中调用store.js的setStateMessage方法的调用格式为:store.setStateMessage()
计算属性与监听器
计算属性:computed
计算属性要解决的问题就是:
我有一个非常复杂的计算表达式,直接将这个表达式放在标签里显得很乱,很复杂。我们为了简洁好看,将这个表达式用花括号{}包装起来,然后给它起个名字,加个参数,它就变成了一个方法了,然后把这个方法放在computed:{ }里面,然后在标签里面如何调用这个非常复杂的计算表达式呢?那就是在双花括号里面写入方法的名字{{方法名}}。
下面这个例子计算:总价=单价×数量×折扣
<template>
<div id="app"><h1>{{message}}</h1><p>单价{{price}}</p><p>数量<button @click="sub">-</button><span>{{quatity}}</span><button @click="add">+</button></p><p> 折扣 {{discount}}</p><h2>总价:{{totalPrice}}</h2>
</div>
</template><script>
export default{data(){return{message:"Hello world",price:99,quatity:0,discount:0.5}},computed:{totalPrice(){return this.price*this.quatity*this.discount}},methods:{sub(){this.quatity--},add(){this.quatity++}}
}
</script><style></style>
监听器:watch
监听器就是监听一个值,然后把这个值变化之后的值传到一个方法里面,方法的名字就是这个值的名字,方法的内容往往是对这个值变化之后的值进行一系列的计算。
例如:监听器要监听value的值,然后就把val变化之后的值传到value(val){ },其中val是value变化后的值。
<template>
<div id="app"><h1>{{message}}</h1><p>单价{{price}}</p><p>数量<button @click="sub">-</button><span>{{quatity}}</span><button @click="add">+</button></p><p> 折扣 {{discount}}</p><h2>总价:{{totalPrice}}</h2>
</div>
</template><script>
export default{data(){return{message:"Hello world",price:99,quatity:0,discount:0.5,totalPrice:0}},// computed:{// totalPrice(){// return this.price*this.quatity*this.discount// }// },watch:{quatity(qu){this.totalPrice = this.price * qu * this.discount}},methods:{sub(){this.quatity--},add(){this.quatity++}}
}
</script><style></style>
计算属性与监听器的区别
多个值改变,为了得到一个值的结果,一般用计算属性(computed)
一个值的改变,会引起多个值的改变,一般用监听器(watch)
实际开发中,大部分时候用computed属性,性能也比较好
但是在用到路由的时候,只能用监听器。