目录
Vue
渐进式 JavaScript 框架
一, 走进 Vue
二, Vue 实例
三, 生命周期钩子
四, Vue 指令
五, 组件
六, Vue-CLI 项目搭建
Vue https://cn.vuejs.org/
渐进式 JavaScript 框架
通过对框架的了解与运用程度, 来决定其在整个项目中的应用范围, 最终可以独立以框架方式完成整个 Web 前端项目
一, 走进 Vue
1,what -- 什么是 Vue
可以独立完成前后端分离式 Web 项目的 JavaScript 框架
2,why -- 为什么要学习 Vue
三大主流框架之一: Angular React Vue
先进的前端设计模式: MVVM
可以完全脱离服务器端, 以前端代码复用的方式渲染整个页面: 组件化开发
3,special -- 特点
单页面 Web 应用
数据驱动
数据的双向绑定
虚拟 DOM
4,how -- 如何使用 Vue
开发版本: https://vuejs.org/js/vue.js
生产版本: https://vuejs.org/js/vue.min.js
- id="app">
- {{ }}
- src="js/vue.min.js">
- new Vue({
- el: '#app'
- })
二, Vue 实例
1,el: 实例
- new Vue({
- el: '#app'
- })
- // 实例与页面挂载点一一对应
- // 一个页面中可以出现多个实例对应多个挂载点
- // 实例只操作挂载点内部内容
2,data: 数据
- id='app'>
- {{ msg }}
- var App = new Vue({
- el: '#app',
- data: {
- msg: '数据',
- }
- })
- console.log(App.$data.msg);
- console.log(App.msg);
3,methods: 方法
- .box { background-color: orange }
- id='app'>
class="box" v-on:click="pClick"> 测试
class="box" v-on:mouseover="pOver"> 测试
- var App = new Vue({
- el: '#app',
- methods: {
- pClick () {
- // 点击测试
- },
- pOver () {
- // 悬浮测试
- }
- }
- })
4,computed: 计算
- id="app">
- type="text" v-model="a">
- type="text" v-model="b">
- {{ c }}
- // 一个变量依赖于多个变量
- new Vue({
- el: "#app",
- data: {
- a: "",
- b: "",
- },
- computed: {
- c: function() {
- // this 代表该 vue 实例
- return this.a + this.b;
- }
- }
- })
5,watch: 监听
- id="app">
- type="text" v-model="ab">
- {{ a }}
- {{ b }}
- // 多个变量依赖于一个变量
- new Vue({
- el: "#app",
- data: {
- ab: "",
- a: "",
- b: "",
- },
- watch: {
- ab: function() {
- // 逻辑根据需求而定
- this.a = this.ab[0];
- this.b = this.ab[1];
- }
- }
- })
6,delimiters: 分隔符
- id='app'>
- ${ msg }
- new Vue({
- el: '#app',
- data: {
- msg: 'message'
- },
- delimiters: ['${', '}']
- })
三, 生命周期钩子
表示一个 vue 实例从创建到销毁的这个过程, 将这个过程的一些时间节点赋予了对应的钩子函数
钩子函数: 满足特点条件被回调的方法
- new Vue({
- el: "#app",
- data: {
- msg: "message"
- },
- beforeCreate () {
- console.log("实例刚刚创建");
- console.log(this.msg
- },
- created () {
- console.log("实例创建成功, data, methods 已拥有");
- console.log(this.msg);
- },
- mounted () {
- console.log("页面已被 vue 实例渲染, data, methods 已更新");
- }
- // 拿到需求 => 确定钩子函数 => 解决需求的逻辑代码块
- })
四, Vue 指令
1, 文本相关指令
- id="app">
- {
- {
- msg
- }
- }
v-text='msg'> 原文本
- v-HTML='msg'>
- v-once>{{ msg }}
- type="text/javascript">
- // 指令: 出现在 HTML 标签中可以被 vue 解析处理的全局属性
- new Vue({
- el: "#app",
- data: {
- msg: "message"
- }
- })
2, 斗篷指令
- type="text/css">
- [v-cloak] { display: none; }
- id="app" v-cloak>
- {{ msg }}
- src="js/vue.min.js">
- type="text/javascript">
- new Vue({
- el: "#app",
- data: {
- msg: "message"
- }
- })
3, 属性指令
- v-bind:abc="abc">
- v-bind:title="'abc'">
- v-bind:class="c1">
- v-bind:class="[c2, c3]">
- v-bind:class="{c4: true|false|var}">
- v-bind:class="[{c5: true}, {c6: flase}]">
- :style="div_style">
- :style="{width:'100px', height:'100px', backgroundColor:'blue'}">
- type="text/javascript">
- new Vue({
- el:"#app",
- data: {
- abc: "abc",
- c1: "p1",
- c2: "p2",
- c3: "p3",
- div_style: {
- width: "200px",
- height: "200px",
- backgroundColor: "cyan"
- }
- }
- })
4, 事件指令
- @click="fn">
- @click="fn()">
- @click="fn($event)">
5, 表单指令
- id="app">
- action=""method="get">
- type="text" name="usr" v-model="in_val">
- type="password" name="ps" v-model="in_val">
- name="info" v-model="in_val">
男: type="radio" name="sex" value="男" v-model="ra_val">
女: type="radio" name="sex" value="女" v-model="ra_val">
- {{ ra_val }}
- type="checkbox" v-model='sin_val' true-value="选中" false-value="未选中" />
- {{ sin_val }}
- type="checkbox" value="喜好男的" name="cless" v-model='more_val' />
- type="checkbox" value="喜好女的" name="cless" v-model='more_val' />
- type="checkbox" value="不挑" name="cless" v-model='more_val' />
- {{ more_val }}
- type="text/javascript">
- new Vue({
- el: '#app',
- data: {
- in_val: '',
- // 默认值可以决定单选框默认选项
- ra_val: '男',
- // 默认值为 true, 单一复选框为选中, 反之 false 为不选中
- sin_val: '',
- // 数组中存在的值对应的复选框默认为选中状态
- more_val: ['喜好女的','不挑']
- }
- })
6, 条件指令
id="app">
@click="toggle"> 显隐切换
- class="box r" v-if="isShow">
- class="box o" v-show="isShow">
- @mouseover="changeWrap(0)">red
- @mouseover="changeWrap(1)">green
- @mouseover="changeWrap(2)">blue
- class="wrap red" v-if="tag == 0" key="0">...
- class="wrap green" v-else-if="tag == 1" key="1">...
- class="wrap blue" v-else key="2">...
- @mouseover="changeMain(0)">red
- @mouseover="changeMain(1)">green
- @mouseover="changeMain(2)">blue
- class="main red" v-show="whoShow(0)">...
- class="main green" v-show="whoShow(1)">...
- class="main blue" v-show="whoShow(2)">...
- type="text/javascript">
- new Vue({
- el: "#app",
- data: {
- isShow: false,
- tag: 0,
- flag: 0
- },
- methods: {
- toggle () {
- this.isShow = !this.isShow;
- },
- changeWrap (num) {
- this.tag = num;
- },
- changeMain (num) {
- // this.flag num
- this.flag = num;
- },
- whoShow (num) {
- // this.flag num
- return this.flag == num;
- }
- }
- })
7, 循环指令
- <div id="app">
- <h1>{{ msg }}</h1>
- <!-- v-for="item in items" -->
- <!-- 遍历的对象: 数组 [] 对象 (字典){} -->
- <ul>
- <li>{{ list[0] }}</li>
- <li>{{ list[1] }}</li>
- <li>{{ list[2] }}</li>
- <li>{{ list[3] }}</li>
- <li>{{ list[4] }}</li>
- </ul>
- <!-- n 为遍历的元素值 -->
- <ul>
- <li v-for="n in list">{{ n }}</li>
- </ul>
- <!-- 一般列表渲染需要建立缓存 -->
- <!-- 列表渲染是循环, 需要赋值变量给 key, 使用 key 需要 v-bind: 处理 -->
- <!-- v-for 变量数组 [] 时, 接收两个值时, 第一个为元素值, 第二个为元素索引 -->
- <ul>
- <li v-for="(n, i) in list" :key="i">value:{{ n }} | index: {{ i }}</li>
- </ul>
- <ul>
- <li>{{ dic['name'] }}</li>
- <li>{{ dic.age }}</li>
- <li>{{ dic.gender }}</li>
- </ul>
- <!-- v-for 变量对象 {} 时, 接收三个值时, 第一个为元素值, 第二个为元素键, 第三个为元素索引 -->
- <ul>
- <li v-for="(v, k, i) in dic" :key="k">value:{{ v }} | key:{{ k }} | index: {{ i }}</li>
- </ul>
- <!-- 遍历的嵌套 -->
- <div v-for="(person, index) in persons" :key="index" style="height: 21px;">
- <div v-for="(v, k) in person" :key="k" style="float: left;">{{ k }} : {{ v }} </div>
- </div>
- </div>
- <script type="text/javascript">
- new Vue({
- el: "#app",
- data: {
- msg: "列表渲染",
- list: [1, 2, 3, 4, 5],
- dic: {
- name: 'zero',
- age: 88888,
- gender: 'god'
- },
- persons: [
- {name: "zero", age: 8},
- {name: "egon", age: 78},
- {name: "liuXX", age: 77},
- {name: "yXX", age: 38}
- ]
- }
- })
- </script>
8,todolist 案例
- <div id="app">
- <div>
- <input type="text" v-model="val">
- <button type="button" @click="submitMsg"> 提交 </button>
- </div>
- <ul>
- <li v-for="(v, i) in list" :key="i" @click="removeMsg(i)">{{ v }}</li>
- </ul>
- {{ list }}
- </div>
- <script type="text/javascript">
- new Vue({
- el: "#app",
- data: {
- val: "",
- list: []
- },
- methods: {
- submitMsg () {
- if (this.val) {
- this.list.push(this.val);
- this.val = ""
- }
- },
- removeMsg(index) {
- this.list.splice(index, 1)
- }
- }
- })
- </script>
五, 组件
每一个组件都是一个 vue 实例
每个组件均具有自身的模板 template, 根组件的模板就是挂载点
每个组件模板只能拥有一个根标签
子组件的数据具有作用域, 以达到组件的复用
1, 根组件
- <div id="app">
- <h1>{{ msg }}</h1>
- </div>
- <script type="text/javascript">
- // 通过 new Vue 创建的实例就是根组件 (实例与组件一一对应, 一个实例就是一个组件)
- // 每个组件组件均拥有模板, template
- var App = new Vue({
- // 根组件的模板就是挂载点
- el: "#app",
- data : {
- msg: "根组件"
- },
- // 模板: 由 "" 包裹的 HTML 代码块, 出现在组件的内部, 赋值给组件的 $template 变量
- // 显式书写模块, 就会替换挂载点, 但根组件必须拥有挂载点
- template: "<div> 显式模板 </div>"
- })
- // App.$template
- </script>
2, 局部组件
- <div id="app">
- <local-tag></local-tag>
- <local-tag></local-tag>
- </div>
- <script>
- var localTag = {
- data () {
- return {
- count: 0
- }
- },
- template: '<button @click="btnAction"> 局部 {{ count }}</button>',
- methods: {
- btnAction () {
- this.count ++
- }
- }
- }
- new Vue({
- el: "#app",
- components: {
- 'local-tag': localTag
- }
- })
- </script>
3, 全局组件
- <div id="app">
- <global-tag></global-tag>
- <global-tag></global-tag>
- </div>
- <script>
- Vue.component('global-tag', {
- data () {
- return {
- count: 0
- }
- },
- template: '<button @click="btnAction"> 全局 {{ count }}</button>',
- methods: {
- btnAction () {
- this.count ++
- }
- }
- })
- new Vue({
- el: "#app"
- })
- </script>
4, 父组件传递数据给子组件
通过绑定属性的方式进行数据传递
- <div id="app">
- <global-tag :sup_data1='sup_data1' :supData2='sup_data2'></global-tag>
- </div>
- <script type="text/javascript">
- Vue.component('global-tag', {
- props:['sup_data1', 'supdata2'],
- template: '<div>{{ sup_data1 }} {{ supdata2 }}</div>'
- })
- new Vue({
- el: '#app',
- data: {
- sup_data1: '数据 1',
- sup_data2: '数据 2'
- }
- })
- </script>
5, 子组件传递数据给父组件
通过发送事件请求的方式进行数据传递
- <div id="app">
- <global-tag @send_action='receiveAction'></global-tag>
- </div>
- <script type="text/javascript">
- Vue.component('global-tag', {
- data () {
- return {
- sub_data1: "数据 1",
- sub_data2: '数据 2'
- }
- },
- template: '<div @click="clickAction"> 发生 </div>',
- methods: {
- clickAction () {
- this.$emit('send_action', this.sub_data1, this.sub_data2)
- }
- }
- })
- new Vue({
- el: '#app',
- methods: {
- receiveAction (v1, v2) {
- console.log(v1, v2)
- }
- }
- })
- </script>
6, 父子组件实现 todoList
- <div id="app">
- <div>
- <input type="text" v-model="val">
- <button type="button" @click="submitMsg"> 提交 </button>
- </div>
- <ul>
- <!-- <li v-for="(v, i) in list" :key="i" @click="removeMsg(i)">{{ v }}</li> -->
- <todo-list v-for="(v, i) in list" :key="i" :v="v" :i="i" @delect_action="delect_action"></todo-list>
- </ul>
- </div>
- <script type="text/javascript">
- Vue.component("todo-list", {
- template: "<li @click='delect_action'><span> 第 {{ i + 1 }} 条: </span><span>{{ v }}</span></li>",
- props: ['v', 'i'],
- methods: {
- delect_action () {
- this.$emit("delect_action", this.i)
- }
- }
- })
- new Vue({
- el: "#app",
- data: {
- val: "",
- list: []
- },
- methods: {
- submitMsg () {
- // 往 list 中添加 input 框中的 value
- if (this.val) {
- this.list.push(this.val);
- this.val = ""
- }
- },
- delect_action(index) {
- this.list.splice(index, 1)
- }
- }
- })
- </script>
六, Vue-CLI 项目搭建
1, 环境搭建
安装 node
官网下载安装包, 傻瓜式安装: https://nodejs.org/zh-cn/
安装 cnpm
NPM install -g cnpm --registry=https://registry.npm.taobao.org
安装脚手架
cnpm install -g @vue/cli
清空缓存处理
NPM cache clean --force
2, 项目的创建
创建项目
vue creat 项目名
- // 要提前进入目标目录 (项目应该创建在哪个目录下)
- // 选择自定义方式创建项目, 选取 Router, Vuex 插件
启动 / 停止项目
- NPM run serve / ctrl+c
- // 要提前进入项目根目录
打包项目
- NPM run build
- // 要在项目根目录下进行打包操作
3, 认识项目
项目目录
dist: 打包的项目目录 (打包后会生成)
node_modules: 项目依赖
public: 共用资源
src: 项目目标, 书写代码的地方
-- assets: 资源
-- components: 组件
-- views: 视图组件
-- App.vue: 根组件
-- main.JS: 入口 JS
-- router.JS: 路由文件
-- store.JS: 状态库文件
vue.config.JS: 项目配置文件 (没有可以自己新建)
配置文件: vue.config.JS
- module.exports={
- devServer: {
- port: 8888
- }
- }
- // 修改端口, 选做
main.JS
- new Vue({
- el: "#app",
- router: router,
- store: store,
- render: function (h) {
- return h(App)
- }
- })
.vue 文件
- <template>
- <!-- 模板区域 -->
- </template>
- <script>
- // 逻辑代码区域
- // 该语法和 script 绑定出现
- export default {
- }
- </script>
- <style scoped>
- /* 样式区域 */
- /* scoped 表示这里的样式只适用于组件内部, scoped 与 style 绑定出现 */
- </style>
4, 项目功能
- vue-router
- {
- path: '/',
- name: 'home',
- // 路由的重定向
- redirect: '/home'
- }
- {
- // 一级路由, 在根组件中被渲染, 替换根组件的 <router-view/> 标签
- path: '/one-view',
- name: 'one',
- component: () => import('./views/OneView.vue')
- }
- {
- // 多级路由, 在根组件中被渲染, 替换根组件的 <router-view/> 标签
- path: '/one-view/one-detail',
- component: () => import('./views/OneDetail.vue'),
- // 子路由, 在所属路由指向的组件中被渲染, 替换该组件 (OneDetail) 的 <router-view/> 标签
- children: [{
- path: 'show',
- component: () => import('./components/OneShow.vue')
- }]
- }
- <!-- router-link 渲染为 a 标签 -->
- <router-link to="/">Home</router-link> |
- <router-link to="/about">About</router-link> |
- <router-link :to="{name:'one'}">One</router-link> |
- <!-- 为路由渲染的组件占位 -->
- <router-view />
- a.router-link-exact-active {
- color: #42b983;
- }
- // router 的逻辑转跳
- this.$router.push('/one-view')
- // router 采用 history 方式访问上一级
- this.$router.go(-1)
- vuex
- // 在任何一个组件中, 均可以通过 this.$store.state.msg 访问 msg 的数据
- // state 永远只能拥有一种状态值
- state: {
- msg: "状态管理器"
- },
- // 让 state 拥有多个状态值
- mutations: {
- // 在一个一个组件中, 均可以通过 this.$store.commit('setMsg', new_msg) 来修改 state 中的 msg
- setMsg(state, new_msg) {
- state.msg = new_msg
- }
- },
- // 让 mutations 拥有多个状态值
- actions: {
- }
- vue-cookie
- // 安装 cookie 的命令
- // NPM install vue-cookie --save
- // 为项目配置全局 vue-cookie
- import VueCookie from 'vue-cookie'
- // 将插件设置给 Vue 原型, 作为全局的属性, 在任何地方都可以通过 this.$cookie 进行访问
- Vue.prototype.$cookie = VueCookie
- // 持久化存储 val 的值到 cookie 中
- this.$cookie.set('val', this.val)
- // 获取 cookie 中 val 字段值
- this.$cookie.get('val')
- axios
- // 安装 axios(Ajax) 的命令
- // NPM install axios--save
- // 为项目配置全局 axios
- import Axios from 'axios'
- Vue.prototype.$Ajax = Axios
- let _this = this
- this.$Ajax({
- method: 'post',
- url: 'http://127.0.0.1:5000/loginAction',
- params: {
- usr: this.usr,
- ps: this.ps
- }
- }).then(function(res) {
- // this 代表的是回调 then 这个方法的调用者 (axios 插件), 也就是发生了 this 的重指向
- // 要更新页面的 title 变量, title 属于 vue 实例
- // res 为回调的对象, 该对象的 data 属性就是后台返回的数据
- _this.title = res.data
- }).catch(function(err) {
- Windows.console.log(err)
- })
- # 用 pycharm 启动该文件模拟后台
- from flask import Flask, request, render_template
- from flask_cors import CORS
- App = Flask(__name__)
- CORS(App, supports_credentials=True)
- @App.route('/')
- def index():
- return "<h1> 主页 </h1>"
- @App.route('/loginAction', methods=['GET', 'POST'])
- def test_action():
- # print(request.args)
- # print(request.form)
- # print(request.values)
- usr = request.args['usr']
- ps = request.args['ps']
- if usr != 'abc' or ps != '123':
- return 'login failed'
- return 'login success'
- if __name__ == '__main__':
- App.run()
来源: http://www.bubuko.com/infodetail-3335599.html