npm install -g vue-cli
(或 npm i -g vue-cli
)vue init webpack demo
项目是基于 webpack 的
npm install
npm run dev
启动成功,浏览器打开<html>
<body>
<div id="app">
<p v-lock>{{msg}}p>
div>
<script src="./js/vue2.5.17.js">script>
<script>
// 创建一个Vue的实例
// 当我们导入包之后,在浏览器的内存中,就多了一个Vue构造函数
// 注意:我们new出来的这个vm对象,就是我们MVVM中VM调度者
var vm = new Vue({
el: "#app", //表示,当前我们new出来的这个Vue实例,要控制页面上的哪个区域
data: {
//这里的data就是MVVM中的M,专门用来保存每个页面的数据的
//data属性中,存放的是el中要用到的数据
msg: "Vue" //通过Vue提供的指令,很方便的就能把数据渲染到页面上,不用在手动操作DOM元素了【前端的Vue、Angular之类的框架不提倡手动操作DOM元素了】
}
});
script>
body>
html>
v-text 指令:绑定 html 元素的文本内容,会覆盖元素中原本的内容,不会解析
v-html 指令:绑定 html 元素的 html 标签,会覆盖元素中原本的内容,会解析
v-model 指令:实现数据的双向绑定
v-once 指令:仅渲染一次
v-show 指令:显示隐藏
v-cloak 指令:当模板未编译完成时,结合 display:none 使用,解决插值表达式闪烁问题。只替换自己的占位符,不会把整个元素的内容清空
v-bind 指令:v-bind:属性名称=“值” 绑定 html 元素的属性 v-bind 可省
v-on 指令:接收方法处理事件 语法 v-on:事件=“函数” 简写 @事件=“函数”
渲染指令
<head>
<style>
[v-cloak] {
display: none;
}
style>
head>
<body>
<div id="app" v-cloak>
<p>您的成绩:{{grade}},{{ grade >= 60?'合格':'不合格'}}p>
<p v-text="grade">p>
<p v-text="msg">p>
<p v-html="msg">p>
<input type="text" v-model="name" />
<h2>hello{{name}}h2>
<p v-once>{{name}}p>
<p>
您的成绩等级:
<span v-if="grade>=80">优秀span>
<span v-else-if="grade>=70">良好span>
<span v-else-if="grade>=60">合格span>
<span v-else>合格span>
p>
<ul>
<li v-for="item in courseList">{{item}}li>
ul>
<ul>
<li v-for="(item,index) in courseList">{{item}}-{{index}}li>
ul>
<p v-for="(value,key,index) in student">{{value}}-{{key}}-{{index}}p>
<img v-bind:src="imgUrl" alt="" />
<img :src="imgUrl" alt="" />
<a href="url" :style="{textDecoration:'none'}">baidua>
div>
body>
除了核心功能默认内置指令(v-model 和 v-show),Vue也允许自定义指令。
普通 DOM 元素进行底层操作要用到自定义指令
建议在给指令的命名采用小驼峰式的命名方式,比如 changeBackgroundColor,在使用的时候,采用烤串式写法 v-change-background-color
一个指令定义对象可以提供如下几个钩子函数:
指令钩子函数会被传入以下参数:
new Vue({
el: "#app",
data: { bgcolor: "orange" },
methods: {},
filters: {},
// 局部注册自定义指令(对指令绑定的元素进行DOM操作),添加directives
directives: {
changeBackgroundColor: {
bind(el, binding) {
console.log("el:", el, ",binding:", binding);
el.style.backgroundColor = binding.value;
}
},
focus: {
inserted(el) {
// 触发元素的focus事件,让其获得焦点
el.focus();
}
}
}
});
// 局部注册过滤器:在Vue实例中添加filters选项
new Vue({
el: "#app",
data: {
price: 17,
ammount: 4,
time: new Date()
},
methods: {},
filters: {
// 过滤器函数:参数1-要格式化的数据,参数2-过滤器参数,必须有返回值(格式化之后的数据)
currency: function(value, op = "$") {
return op + value.toFixed(2);
},
date: function(value) {
// 常用日期过滤器 日期格式:yyyy-MM-dd HH:mm:ss
let y = value.getFullYear();
let m = value.getMonth() + 1;
let d = value.getDate();
let h = value.getHours();
let mi = value.getMinutes();
let s = value.getSeconds();
return `${y}-${m < 10 ? "0" + m : m}-${d < 10 ? "0" + d : d} ${
h < 10 ? "0" + h : h
}:${mi < 10 ? "0" + mi : mi}:${s < 10 ? "0" + s : s}`;
},
// 对数值进行格式化,保留小数位(默认3位)10,000.000
number: function(value, n = 3) {
return value.toFixed(n);
}
// TODO filter过滤器,orderBy
}
});
组件中的数据共有三种形式:data、props、computed
注册组件(注意:html 中不能使用单标记)
// (1)注册全局组件,所有Vue实例中可以直接引用此组件
/*
参数1:组件名称,命名以大驼峰或-连接(小写单词)
参数2:组件选项,template,data等
例:MyComponent my-component
*/
Vue.component("my-compoent", {
template: "Welcome to Vue!"
});
<div id="app">
<my-compoent>my-compoent>
div>
// (2)注册局部组件,仅当前Vue实例可用
const My = {
template: "{{msg}}
",
// data必须是函数
data() {
//一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝
return {
msg: "Hello Vue!"
};
}
};
// 建议将组件封装在一个独立的.js或.vue文件里面
new Vue({
el: "#app",
data: {},
// 在Vue实例中添加componments选项来注册局部组件
components: {
My // My:My
}
});
<div id="app">
<My>My>
div>
组件封装
将其封装至单独的.vue 文件中放在 components 文件夹下
单独的组件.vue 文件结构如下:
<template>
</template>
<style scoped>
/* scoped局部作用域,只在当前vue文件中生效 */
</style>
<script>
export default {//默认导出vue文件,其中为vue实例的选项
//el不要加,自动挂载到template上
//data要写成函数形式
data(){
return{
}
}
}
</script>
组件生命周期
父子组件间的通信 props down, events up
父组件通过 props 向下传递数据给子组件
子组件向父组件传值(通过事件形式)
$emit
触发 组件传递过来的方法,挂载在当前实例上的事件,还可以传递参数//父组件App.vue
<template>
<div id="app">
<img src="./assets/logo.png">
<!-- 通过自定义属性,将值向下传递给子组件 -->
<HelloWorld :number="count" @updCount="update"/>
<button @click="update">App中更新</button>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld'
export default {
name: 'App',
components: {
HelloWorld
},
data(){
return {
count: 1
}
},
methods:{
update(a,b,c){
console.log(a,b,c);
this.count+=a;
}
}
}
</script>
<style>
</style>
//子组件 HelloWorld.vue
<template>
<div class="hello">
<p>计数器:{{number}}</p>
<button @click="updateProps">子组件更新数据</button>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
}
},
props: ['number'],
methods:{
updateProps(){
// props中的数据是只读的
// this.number++;//不要直接更改props数据
// Events Up触发父组件的事件,让父组件去更新
// this.$emit('updCount');
this.$emit('updCount',2,3,4);
}
}
}
</script>
<style scoped>
</style>
this.\$route
this.\$router
npm i vue-router --save
//引入 vue 的路由管理器
import VueRouter from "vue-router";
// 引入路由组件
import Login from "@/components/Login";
import Registe from "@/components/Registe";
// 安装路由的功能
Vue.use(VueRouter);
// 创建一个路由管理器对象
const router = new VueRouter({
// 添加配置参数routes
routes: [
// path: 路由标记(路径),component: 路由标记对应的组件
{ path: "/log", component: Login },
{ path: "/reg", component: Registe },
// 根路由
{ path: "/", redirect: "/log" }
]
});
export default router;
<!-- 路由导航:会渲染成a标签 -->
<router-link to="/log">登录</router-link>
<router-link to="/reg">注册</router-link>
<!-- 路由出口:路由匹配到的组件会渲染在这里 -->
<router-view></router-view>
带参路由
//router下index.js文件配置路由
import Vue from 'vue'
import Router from 'vue-router'
import PhonesList from '@/pages/PhonesList'
import Detail from '@/pages/Detail'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'PhonesList',
component: PhonesList
},
{
path: '/detail/:id', //路由带参数,在路由标记后面添加 /:参数名称
component: Detail
}
]
})
//PhonesList.vue传递参数
<template>
<div>
<ul>
<li v-for="item in phones" :key="item.age">
<h3><router-link :to="`/detail/${item.id}`">{{item.name}}</router-link></h3>
<p>{{item.snippet}}</p>
</li>
</ul>
</div>
</template>
<script>
export default {
data(){return {phones: []}},
created(){
// 请求所有的手机列表数据
this.$axios.get('/static/data/phones.json').then(resp => {
this.phones = resp.data;
});
}
}
</script>
<style scoped>
</style>
//Detail.vue 接收参数
<template>
<div>
<h4>{{phone.name}}</h4>
<p>{{phone.description}}</p>
<router-link to="/">返回首页</router-link>
</div>
</template>
<script>
export default {
data(){return {phone: {}}},
beforeMount(){
// 所有的组件中都可以访问路由管理器this.$router(VueRouter对象),当前路由this.$route
// 当前手机的id参数
let id = this.$route.params.id;
this.$axios.get(`/static/data/${id}.json`).then(resp => {
this.phone = resp.data
})
}
}
</script>
<style scoped>
</style>
路由嵌套
//router下index.js配置路由
import Vue from 'vue'
import Router from 'vue-router'
import Nav from '@/components/Nav'
import TopicList from '@/components/TopicList'
Vue.use(Router)
export default new Router({
routes: [
/*
重定向也通过 routes 配置
{ path: '/a', redirect: '/b’ } //从 /a 重定向到 /b
*/
{
path:'/nav',
component: Nav,
// 配置子路由
children:[
{
// path:'/nav/TopicList/:tab',//访问的路由标记
path:'TopicList/:tab',//访问的路由标记/nav/TopicList
component: TopicList
},
// 默认子路由
{
path:'',
redirect:'TopicList/all'
}
]
}
]
})
//App.vue
<template>
<div id="app">
<img src="./assets/logo.png">
<router-link to="/nav">导航</router-link>
<router-view/>
</div>
</template>
//Nav.vue外层
<template>
<div>
<ul>
<li><router-link to="/nav/TopicList/all">全部</router-link></li>
<li><router-link to="/nav/TopicList/good">精华</router-link></li>
<li><router-link to="/nav/TopicList/ask">问答</router-link></li>
</ul>
<router-view></router-view>
</div>
</template>
//TopicList.vue被嵌套的组件
<template>
<div>
<h2>{{tit}}</h2>
</div>
</template>
<script>
export default {
data(){return {tit: ""};},
created() {console.log("TopicList created");},
watch: {
$route: { // 监听当前路由的变化
handler: function() {this.tit = this.$route.params.tab;
// 执行异步任务,比如请求后端接口中的数据
},immediate:true}}
};
</script>
<style scoped>ul{list-style: none;}</style>
export default{
data(){},
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不能获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1和/foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}
//router.vue下index.js
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Login from '@/components/Login'
import New from '@/components/New'
import Cookies from 'js-cookie'
Vue.use(Router)
const router = new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
{
path: '/new',
name: 'New',
component: New,
// 添加路由元信息
meta:{
requireLogin:true
}
},
{
path: '/log',
name: 'Login',
component:Login,
meta:{
requireLogin:false
}
}
]
})
router.beforeEach((to, from, next) => {
console.log('当前导航正要离开的路由',from,'即将要进入的目标',to);
if(to.meta.requireLogin){/
let username=Cookies.get('username');
if(username){
next();
}else{
alert('请先登录');
next('/log');
}
}else{
next();
}
})
router.afterEach((to, from) => {
console.log('afterEach',to);
})
export default router;
//首页Helloworld.vue
<template>
<div class="hello">
<h1>{{ msg }}</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data(){return {msg: '欢迎来到博客园'}}
}
</script>
<style scoped>
</style>
//tab切换页面App.vue
<template>
<div id="app">
<ul>
<li><router-link to="/">首页</router-link></li>
<li><router-link to="/New">新随笔</router-link></li>
</ul>
<!-- 渲染位置 -->
<router-view/>
</div>
</template>
<script>
export default {name: "App"};
</script>
<style>
</style>
//Login.vue主要代码登录页
<template>
<div>
<form>
<input type="text" placeholder="账号" v-model="account" />
<input type="password" placeholder="密码" v-model="password" />
<input type="button" value="登录" @click="login" />
form>
div>
template>
<script>
import Cookies from "js-cookie";
export default {
data() {
return {
account: "",
password: ""
};
},
methods: {
login() {
// 在cookie中保存登录的用户信息
console.log("登录成功");
Cookies.set("username", this.account);
// 路由跳转
this.$router.push("/New");
}
}
};
</script>
import store from './store'
new Vue({
el: '#app',
router,
components: { App },
template: ' ',
// 注册store,在Vue组件内部通过this.$store来访问
store,//store:store
})
import Vuex from 'vuex'
// 安装Vuex,在Vue实例中才能使用Vuex的功能
Vue.use(Vuex)
// Vuex中的核心是Store(仓库,存储的是组建的公共状态)
// 创建Store对象
const store=new Vuex.Store({
/*
四个属性
- state状态(组件之间传递数据或组件的状态)
- getters计算属性(将state中的某状态过滤后获取新状态)
- mutations 存放如何更改状态,只能进行同步操作
- actions commit mutations中方法来改变状态(不直接更改状态),可以进行异步操作。
*/
})
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
new Vue({
el: '#app',
render: h => h(App)
})
{
"presets": [["es2015", { "modules": false }]],
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
import Vue from 'vue';
import { Button, Select } from 'element-ui';
import App from './App.vue';
Vue.component(Button.name, Button);
Vue.component(Select.name, Select);
/* 或写为
* Vue.use(Button)
* Vue.use(Select)
*/
new Vue({
el: ‘#app’,
render: h => h(App)
});
<el-row :gutter="10">
<el-col :span="6" class="bg-purple">javael-col>
<el-col :span="6" class="bg-purple">webel-col>
<el-col :span="6" class="bg-purple">Big Datael-col>
<el-col :span="6" class="bg-purple">Pythonel-col>
el-row>
<el-row>
<el-col :span="10" class="bg-purple">oneel-col>
<el-col :span="10" :off-set="4" class="bg-purple">twoel-col>
el-row>
div>
<i class="el-icon-eleme" style="font-size:20px;color:blue;">i>
<el-button type="primary">主要按钮el-button>
<el-button type="success">成功按钮el-button>
<el-button type="danger">危险按钮el-button>
<el-button type="danger" plain>危险按钮el-button>
<el-button type="danger" round size="mini">危险按钮el-button>
<el-button type="danger" circle icon="el-icon-delete">el-button>
<el-button type="primary" :loading="true">登录中el-button>
<el-button type="primary" icon="el-icon-search">搜索el-button>
<el-button type="primary">上传<i class="el-icon-upload el-icon--right">i>el-button>
<template>
<div>
<el-form label-width="80px" :model="user">
<el-form-item label="账号">
<el-input v-model="user.account"></el-input>
</el-form-item>
<el-form-item label="密码">
<el-input v-model="user.password" show-password></el-input>
</el-form-item>
<el-form-item label="确认密码">
<el-input v-model="user.confirmPass" show-password></el-input>
</el-form-item>
<el-form-item label="性别">
<el-radio v-model="user.sex" :label="1">男</el-radio>
<!-- 数值 :label -->
<el-radio v-model="user.sex" :label="0">女</el-radio>
</el-form-item>
<el-form-item label="爱好">
<el-checkbox-group v-model="user.hobby">
<el-checkbox label="game">游戏</el-checkbox>
<el-checkbox label="旅游"></el-checkbox>
<el-checkbox label="编程"></el-checkbox>
<el-checkbox label="购物"></el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="居住地">
<el-select v-model="user.home" placeholder="请选择">
<el-option label="杭州" value="hangzh"></el-option>
<el-option label="宁波" value="ningb"></el-option>
</el-select>
</el-form-item>
<el-button @click="registe">登录</el-button>
</el-form>
</div>
</template>
<script>
export default {
data(){
return{
user:{
account:'',
password:'',
confirmPass:'',
sex:1,
hobby:[],
home:''
}
}
},
methods: {
registe(){
console.log(this.user);
}
},
}
</script>
<style scoped>
</style>