Node.js安装教程:
Node.js安装教程_安装nodejs_微风粼粼的博客-CSDN博客
Vue
Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架。
它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面。
无论是简单还是复杂的界面,Vue 都可以胜任。
三大框架
vue 尤雨溪
react facebook
angular 谷歌
vue的前置知识点
Html、Css、Js
了解Node、npm
webpack打包工具
使用Vue
1,直接引入vue.js文件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<!-- <script src="https://unpkg.com/vue@next"></script> -->
<script src="js/v2.6.10/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
{{message}}
<!-- 拼接 -->
<h1>你好:{{name}}</h1>
<h1>{{"年龄:"+age}}</h1>
{{gender}}
<!-- 绑定事件 -->
<button v-on:click="sayHello">点击</button>
<button @click="sayHello">点击</button>
<!-- 绑定属性 v-bind -->
<img v-bind:src="url" width="50px" alt="">
<img :src="url" width="50px" alt="">
<button @click="changeImg">点击换图</button>
<!-- 计数器 -->
<button @click="subtract">-</button>
{{num}}
<button @click="add">+</button>
</div>
</body>
<script>
new Vue({
el:"#app",
data:{
message:"hello vue",
name:"jack",
age:"23",
gender:"男",
url:"img/动漫 - 35.jpg",
num:"0"
},
// 函数
methods:{
sayHello(){
alert("hello");
},
changeImg(){
this.url = "img/卡通 - 6.jpg";
},
subtract(){
if(this.num > 0){
this.num--;
}else{
alert("数字不能小于0!");
}
},
add(){
if(this.num < 10){
this.num++;
}else{
alert("数字不能大于10!");
}
}
}
})
</script>
</html>
使用脚手架创建vue项目
使用vue/cli工具创建,前提需要电脑上安装好node环境
第一种方式:
安装之前,可以安装一个cnpm插件,会将下载的内容移到国内的站点
打开cmd窗口输入:npm install -g cnpm --registry=https://registry.npm.taobao.org
cnpm install -g @vue/cli
第二种方式:
步骤 :
1,先安装vue/cli工具 : npm install -g @vue/cli
2, 切换到项目位置,打开cmd窗口,使用vue/cli去创建项目 : vue create 项目名
创建好项目后
执行后,弹出如下界面
在浏览器中输入地址,访问即可
Vue的项目结构
node_modules : 项目启动的依赖文件
public目录下:
index.html : vue项目首页的入口文件,将来vue文件中的标签代码,其实都被渲染到这个文件中,然后做展示
src目录 :src目录就是开发目录,基本上后面开发中做的事情,都在这个目录下
assets :将来放一些静态资源,比如图片资源等
components:用来存放一些被引用的组件文件
router:路由的配置文件,负责管理将来页面的跳转配置,在这个目录中的index.js中配置
views:存放一些使用的组件文件
app.vue : vue项目的入口vue组件,将来代码可以直接写在这个app.vue中,就能展示到页面上
main.js : 项目的核心配置文件,组织了App.vue文件被渲染到index.html的创建
面试题: main.js的作用,用来绑定渲染App.vue组件
//1,这里是es6的语法,表示vue实例选项对象的render方法,作为一个函数,接收h
//作为传入的参数,返回 h(App)
//2,vue在创建Vue实例,通过调用render方法来渲染实例的DOM树
//3,Vue对象在调用render方法的时候,会使用createElement函数作为参数
//然后createElement函数会以App,作为参数,进行调用,处理
//4,最后,Vue对象会将渲染好的结果,绑定到#app这个节点中,其实就是之前
//public目录中的index.html文件中
vue组件中,代码的编写方式
<template>
<div id="app">
<nav>
<h1>vue的项目</h1>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</nav>
<!-- <router-view/> -->
<h2>{{message}}</h2>
<h3>{{name}}</h3>
<h3>{{age}}</h3>
<h3>{{user}}</h3>
<h3>{{user.username}}</h3>
<h3>{{user.age}}</h3>
<button @click="sayHello">点击</button>
<button @click="subtract">-</button>
{{num}}
<button @click="add">+</button>
</div>
</template>
<script>
export default{
data() {
return{
message:"你好 Vue",
name:"alice",
age:23,
user:{username:"tom",age:21},
num:0
}
},
methods:{
sayHello(){
alert("hello")
},
subtract(){
if(this.num > 0){
this.num--;
}else{
alert("数字不能小于0!")
}
},
add(){
if(this.num < 10){
this.num++;
}else{
alert("数字不能大于10!")
}
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
nav {
padding: 30px;
}
nav a {
font-weight: bold;
color: #2c3e50;
}
nav a.router-link-exact-active {
color: #42b983;
}
</style>
vue中常用指令
vue指令指的是 ,vue以v开头的一些命令属性
v-bind : 绑定事件的 ,可以简写成冒号 :
比如, <img v-bind:src = "xxxx"> 简写成 <img :src = "xxxx">
v-on :绑定事件的,简写成@
比如, <button v-on:click="触发函数名"> 简写成 <button @:click="触发函数名">
条件判断指令,控制元素的可见性,值是布尔值,true就是显示,false就是隐藏
v-if : 如果设为false,不渲染dom,这个元素就直接不存在
v-show:如果设为false,渲染dom,表示是将display设为none,元素本身还是存在的
<template>
<div id="app">
<nav>
<h1>vue的项目</h1>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</nav>
<button @click="islogin">判断用户是否登录</button>
<p v-if="isLogin">你好,欢迎你登录 {{name}}</p>
<p v-show="false">你好,欢迎你2</p>
</div>
</template>
<script>
export default{
data() {
return{
name: "jack",
isLogin:false
}
},
methods:{
sayHello(){
alert("hello");
},
islogin(){
if(this.name != "" || this.name != null){
this.isLogin = true;
}else{
this.isLogin = false;
}
}
}
}
</script>
循环指令 v-for
v-for : 可以用来获取集合、数组中的数据,把数据单独展示
<template>
<div class="about">
<h1>This is an about page</h1>
<ul>
<li v-for="(fruit,index) in fruits" :key="index">
<p>水果编号:{{index+1}}-->水果名称:{{fruit}}</p>
</li>
</ul>
<table>
<tr>
<th>编号</th>
<th>姓名</th>
<th>年龄</th>
<th>性别</th>
</tr>
<tr v-for="(s,i) in students" :key="i">
<td>{{i+1}}</td>
<td>{{s.name}}</td>
<td>{{s.age}}</td>
<td>{{s.gender}}</td>
</tr>
</table>
</div>
</template>
<script>
export default{
data() {
return{
fruits:["香蕉","苹果","梨子"],
students:[
{name:"jack",age:22,gender:"男"},
{name:"tom",age:21,gender:"男"},
{name:"lucy",age:20,gender:"女"}
]
}
}
}
</script>
Vue中的组件开发
将来开发大型页面的时候,如果将代码都写在一个页面中,代码会比较复杂
一般将来会用组件嵌套的方式开发项目
一般将来被别的组件引用的组件,都是放在components目录下
组件的编写 :
命名: 和写Java中的类名类似,推荐使用大写字母开头,大驼峰式的写法,防止和原html中的标签冲突
步骤 :
1,在components目录下新建一个vue文件
2,注册组件
3,引入0
组件传值
1,父组件向子组件传递数据
2,子组件向父组件传递数据
3,非父子关系数据传递
父组件向子组件传递数据 :使用属性传递
1,编写父组件的代码
先注册使用子组件,在子组件中绑定自定义属性,并传递需要发送的数据
子组件向父组件传值 : 使用自定义的事件
子组件不能直接改变父组件的值,只能通过调用父组件的自定义事件来传值
$emit ,可以让父组件监听到自定义的事件
子组件Child.vue
<template>
<div>
<h1>这是child子组件</h1>
<button @click="sendData">点击传递数据</button>
</div>
</template>
<script>
export default{
data(){
return{
childData:"子组件的数据,可以传递到父组件中"
}
},
methods:{
sendData(){
this.$emit("childEvent",this.childData);
}
}
}
</script>
父组件App.vue
<template>
<div id="app">
<h1>这是App.vue组件</h1>
<Child @childEvent="changeDate"></Child>
来自子组件的数据:{{dataChild}}
</div>
</template>
<script>
import Child from "./components/Child.vue"
export default{
components:{
Child
},
data() {
return{
message:"父级的数据,传递到子级中",
dataChild:""
}
},
methods:{
changeDate(childData){
this.dataChild = childData;
}
}
}
</script>
购物车的计价案例
Carts.vue 购物车组件
Counter.vue 计数器组件
将来会在购物车中,引用计数器组件, Carts.vue是父组件 ,Counter.vue是子组件
store.js
export default{
state:{
fruits:[
{name:"苹果",price:5.88,count:0},
{name:"香蕉",price:3.88,count:0},
{name:"梨子",price:4.88,count:0}
]
},
reset(){
this.state.fruits.map(v=>{
v.count = 0;
})
},
sub(i){
this.state.fruits[i].count--;
},
add(i){
this.state.fruits[i].count++;
}
}
App.vue
<template>
<div id="app">
<nav>
<h1>vue的项目</h1>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</nav>
<Carts></Carts>
<Control></Control>
<!-- <router-view/> -->
</div>
</template>
<script>
import Carts from "./components/Carts.vue"
import Control from "./components/Control.vue"
export default{
components:{
Carts,
Brother,
Sister,
Control
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
nav {
padding: 30px;
}
nav a {
font-weight: bold;
color: #2c3e50;
}
nav a.router-link-exact-active {
color: #42b983;
}
</style>
Carts.vue
<template>
<div>
<h1>购物车</h1>
<ul>
<li v-for="(v,i) in soreDate.fruits" :key="i">
{{v.name}} 单价: {{v.price}}
<Counter :count = "v.count" :index="i"
@sub="sub" @add="add"></Counter>
</li>
</ul>
<h1>总价格:{{totalPrice}}</h1>
</div>
</template>
<script>
import Counter from "./Counter.vue"
import store from "../store.js"
export default{
components:{Counter},
data() {
return{
soreDate:store.state
}
},
methods:{
sub(index){
store.sub(index);
},
add(index){
store.add(index);
}
},
computed:{
totalPrice(){
let total = 0;
this.soreDate.fruits.map(v=>{
total += v.price * v.count;
})
return total.toFixed(2);
}
}
}
</script>
<style>
</style>
Counter.vue
<template>
<div>
<button @click="sub">-</button>
{{count}}
<button @click="add">+</button>
</div>
</template>
<script>
export default{
props:["count","index"],
methods:{
sub(){
this.$emit("sub",this.index)
},
add(){
this.$emit("add",this.index)
}
}
}
</script>
<style>
</style>
Control.vue
<template>
<div>
<button @click="reset">重置数据</button>
</div>
</template>
<script>
import store from "../store.js"
export default{
methods:{
reset(){
store.reset();
}
}
}
</script>
<style>
</style>
非父子组件之间的传值,通过定义一个共享的js文件
store.js
export default{
//这个js文件用来管理非父子关系之间的数据
//把数据存在这里后,让兄弟组件都能访问到
//从而实现数据的共享
//state:表示状态的意思,共享的数据将来就存在这个里面
//组件可以访问,也可以改变这个数据
state:{
message:"这是非父子关系值传递"
},
setStateDate(str){
this.state.message = str;
}ate.fruits[i].count++;
}
}
Brother.vue
<template>
<div>
<h1>这是brother兄弟组件</h1>
<button @click="changeData">改变数据</button>
<p>{{storeData.message}}</p>
</div>
</template>
<script>
import store from "../store.js"
export default{
data() {
return{
storeData:store.state,
brotherData:"这是brother组件的数据"
}
},
methods:{
changeData(){
store.setStateDate(this.brotherData);
}
}
}
</script>
<style>
</style>
Sister.vue
<template>
<div>
<h1>这是sister组件</h1>
<button @click="sisterData">改变数据</button>
<p>{{storesData.message}}</p>
</div>
</template>
<script>
import store from "../store.js"
export default{
data() {
return{
storesData:store.state,
sisterDate:"这是sister组件的数据"
}
},
methods:{
sisterData(){
store.setStateDate(this.sisterDate);
}
}
}
</script>
<style>
</style>
App.vue
<template>
<div id="app">
<nav>
<h1>vue的项目</h1>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</nav>
<Brother></Brother>
<Sister></Sister>
</div>
</template>
<script>
import Brother from "./components/Brother.vue"
import Sister from "./components/Sister.vue"
export default{
components:{
Brother,
Sister
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
nav {
padding: 30px;
}
nav a {
font-weight: bold;
color: #2c3e50;
}
nav a.router-link-exact-active {
color: #42b983;
}
</style>
计算属性和侦听器
计算属性:computed
computed属性中和data属性一样,可以将定义的值、函数直接绑定在 插值表达式{{}}
将来如果某些值,需要通过计算才能获取的话,可以使用计算属性
<template>
<div id="app">
<nav>
<h1>vue的项目</h1>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</nav>
<h1>计算属性</h1>
<p>{{title}}</p>
<p>{{message}}</p>
<p>姓名:{{firstName+lastName}}</p>
<p>姓名:{{name}}</p>
<!-- 复杂的计算 总价 = 单价 * 数量 * 折价 - 优惠券 -->
<p>单价:{{price}}</p>
<p>数量:{{count}}
<button @click="sub">-</button>
<button @click="add">+</button>
</p>
<p>折扣:{{discount}}</p>
<p>总价:{{totalPrice}}</p>
</div>
</template>
<script>
export default{
components:{
},
data() {
return {
title:"hello",
firstName:"张",
lastName:"三",
price:999,
count:1,
discount:0.5
}
},
computed:{
message(){
return "hello,computed"
},
name(){
return this.firstName + this.lastName
},
totalPrice(){
return this.price * this.count * this.discount
}
},
methods:{
add(){
this.count++
},
sub(){
this.count--
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
nav {
padding: 30px;
}
nav a {
font-weight: bold;
color: #2c3e50;
}
nav a.router-link-exact-active {
color: #42b983;
}
</style>
侦听器:watch
watch将来主要用来侦听某个属性的变化
<template>
<div id="app">
<nav>
<h1>vue的项目</h1>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</nav>
<Sister></Sister> -->
<h1>计算属性</h1>
<p>{{title}}</p>
<p>{{message}}</p>
<p>姓名:{{firstName+lastName}}</p>
<p>姓名:{{name}}</p>
<!-- 复杂的计算 总价 = 单价 * 数量 * 折价 - 优惠券 -->
<p>单价:{{price}}</p>
<p>数量:{{count}}
<button @click="sub">-</button>
<button @click="add">+</button>
</p>
<p>折扣:{{discount}}</p>
<p>总价:{{totalPrice}}</p>
</div>
</template>
<script>
export default{
components:{
},
data() {
return {
title:"hello",
firstName:"张",
lastName:"三",
price:999,
count:0,
discount:0.5,
totalPrice:0
}
},
computed:{
message(){
return "hello,computed"
},
name(){
return this.firstName + this.lastName
},
// totalPrice(){
// return this.price * this.count * this.discount
// }
},
methods:{
add(){
this.count++
},
sub(){
this.count--
}
},
watch:{
count(val){
console.log(val);
this.totalPrice = this.price * val * this.discount;
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
nav {
padding: 30px;
}
nav a {
font-weight: bold;
color: #2c3e50;
}
nav a.router-link-exact-active {
color: #42b983;
}
</style>
computed和watch比较 :
将来如果需要观察,某个值发生改变,影响多个值,可以使用watch(观察一个值)
如果多个值发生改变,为了得到一个结果,使用computed
实际开发中,使用computed较多
生命周期钩子
每个 Vue 组件实例在创建时都需要经历一系列的初始化步骤,比如设置好数据侦听,编译模板,挂载实例到 DOM,以及在数据改变时更新 DOM。
在此过程中,它也会运行被称为生命周期钩子的函数,让开发者有机会在特定阶段运行自己的代码。
每个阶段可以执行的钩子,其实就是一个函数
App.vue
<template>
<div id="app">
<nav>
<h1>vue的项目</h1>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</nav>
<Sister></Sister> -->
<h1>计算属性</h1>
<p>{{title}}</p>
<p>{{message}}</p>
<p>姓名:{{firstName+lastName}}</p>
<p>姓名:{{name}}</p>
<!-- 复杂的计算 总价 = 单价 * 数量 * 折价 - 优惠券 -->
<p>单价:{{price}}</p>
<p>数量:{{count}}
<button @click="sub">-</button>
<button @click="add">+</button>
</p>
<p>折扣:{{discount}}</p>
<p>总价:{{totalPrice}}</p>
</div>
</template>
<script>
export default{
components:{
},
data() {
return {
title:"hello",
firstName:"张",
lastName:"三",
price:999,
count:0,
discount:0.5,
totalPrice:0
}
},
computed:{
message(){
return "hello,computed"
},
name(){
return this.firstName + this.lastName
},
// totalPrice(){
// return this.price * this.count * this.discount
// }
},
methods:{
add(){
this.count++
},
sub(){
this.count--
},
setData(){
this.title = "mounted";
}
},
watch:{
count(val){
console.log(val);
this.totalPrice = this.price * val * this.discount;
}
},
beforeCreate() {
console.log("vue示例创建之前执行这里的内容...");
console.log(this.title);
},
created() {
console.log("vue示例创建之后执行这里的内容...");
console.log(this.title); //进入xxx首页,使用created
this.setData();
},
mounted() {
console.log("vue示例初始化之后执行这里的内容...");
this.setData();
},
beforeUpdate() {
console.log("数据改变之前执行这里");
console.log(this.count);
},
updated() {
console.log("数据改变之后执行这里");
console.log(this.count);
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
nav {
padding: 30px;
}
nav a {
font-weight: bold;
color: #2c3e50;
}
nav a.router-link-exact-active {
color: #42b983;
}
</style>
Vue中的表单
v-model 表单数据的双向绑定
App.vue
<template>
<div id="app">
<h1>{{username}}</h1>
<h1>{{password}}</h1>
用户名:<input type="text" v-model="username" > <br>
密码:<input type="text" v-model="password" ><br />
<button @click="submit">提交</button>
<button @click="bind">绑定数据到输入框</button>
</div>
</template>
<script>
export default{
data() {
return{
username : "",
password: ""
}
},
methods:{
submit(){
console.log(this.username + "--" + this.password)
},
bind(){
this.username = "tom";
this.password = "123";
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
nav {
padding: 30px;
}
nav a {
font-weight: bold;
color: #2c3e50;
}
nav a.router-link-exact-active {
color: #42b983;
}
</style>
复杂表单提交
<template>
<div id="app">
<form @submit.prevent="postData">
<div>
用户名: <input type="text" v-model="formData.username">
</div>
<div>
密码: <input type="text" v-model="formData.password">
</div>
<div>
爱好:
<select v-model="formData.hobby">
<option value="game">游戏</option>
<option value="study">学习</option>
</select>
</div>
<div>
性别:
男 <input type="radio" value="男" v-model="formData.gender">
女 <input type="radio" value="女" v-model="formData.gender">
</div>
<div>
课程:
数学 <input type="checkbox" value="数学" v-model="formData.course">
语文 <input type="checkbox" value="语文" v-model="formData.course">
英语 <input type="checkbox" value="英语" v-model="formData.course">
</div>
<button>提交</button>
</form>
</div>
</template>
<script>
export default{
data() {
return{
formData:{
username:"",
password:"",
hobby:"",
gender:"",
course:[]
}
}
},
methods:{
postData(){
console.log(this.formData)
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
nav {
padding: 30px;
}
nav a {
font-weight: bold;
color: #2c3e50;
}
nav a.router-link-exact-active {
color: #42b983;
}
</style>
路由
路由主要用来控制页面跳转,以及数据的访问的
this.$router.push("/blog"); 自己定义跳转页面的页面,一般用来写在执行某个操作完成后,跳转页面
this.$route 实现数据传递
Home.vue
<template>
<div>
<h1>这是首页页</h1>
<button @click="toBlog">跳转</button>
</div>
</template>
<script>
export default{
methods:{
toBlog(){
this.$router.push("/blog");
}
}
}
</script>
<style>
</style>
Blog.vue
<template>
<div>
<h1>这是博客页</h1>
</div>
</template>
<script>
</script>
<style>
</style>
Video.vue
<template>
<div>
<h1>这是视频页</h1>
</div>
</template>
<script>
</script>
<style>
</style>
index.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import HomeView from '../views/HomeView.vue';
import Home from '../views/Home.vue';
import Blog from '../views/Blog.vue';
import Video from '../views/Video.vue';
Vue.use(VueRouter);
const routes = [
// {
// path: '/',
// name: 'home',
// component: HomeView,
// },
{
path: '/',
name: 'home',
component: Home,
},
{
path: '/blog',
name: 'blog',
component: Blog,
},
{
path: '/video',
name: 'video',
component: Video,
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue'),
},
];
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes,
});
export default router;
App.vue
<template>
<div id="app">
<div id="nav">
<router-link to="/">首页</router-link> ||
<router-link to="/blog">博客</router-link> ||
<router-link to="/video">视频</router-link>
</div>
<router-view></router-view>
</div>
</template>
展示: