npm(nodejs package manager)、webpack、Vue组件、Vue脚手架开发工具、Vue Router的使用、Vuex的使用、使用Django前后端交互

13.8 npm(nodejs package manager)

使用命令行安装包:
1. cd切换到项目目录下,执行初始化操作 npm init/npm init -y
2. 安装其他依赖包
npm install jquery
npm install jquery@1.11.13
npm install jquery -g       全局安装
npm install bootstrap@3 -D  开发环境下
marked包安装和使用    npm install marked -D
npm install vuex -D
3. 卸载包     npm uninstall 包名
4. 更新npm    npm install npm@latest
5. npm安装包慢的解决办法:
    1.安装cnpm包 :https://npm.taobao.org/
    npm install -g cnpm --registry=https://registry.npm.taobao.org
    2. 配置npm源为阿里源
    npm config set registry https://registry.npm.taobao.org/

在当前项目下生成文件:node_moduels(包含用npm导入的jQuery包等)、package.json、pack-lock.json(包含导入包的信息)

index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <script src="./node_modules/jquery/dist/jquery.min.js"></script>
    <script>
        $.each([11,22,33], function(k,v){
            console.log(k,v)
        })
    </script>
</body>
</html>

13.9 webpack

为什么要有webpack?
1. JS中不存在模块化的概念
2. 安装和使用
npm install webpack -g          --> 全局安装
npm install webpack-cli -g
3. webpack进阶:https://webpack.js.org/

在当前项目下生成文件:dist(包含main.js,将项目下的依赖关系文件打包保存在main.js文件中)、node_moduels(包含用npm导入的jQuery包等)、package.json、pack-lock.json(包含导入包的信息)

x.js:

var alex = 'sb';
var login = true;
module.exports = {alex}

y.js:

var obj = require('./x')
var jquery = require('jquery')
console.log(obj);   //sb
jquery.each([11,22,33,44], function(k,v){
    console.log(k,v)
})

main.html:

<body>
<script src="./dist/main.js"></script>
</body>

13.10Vue组件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
    <div id="app">
        <button-counter></button-counter>
        <button-counter></button-counter>
        <button-counter></button-counter>
        <component-a></component-a>
        <ComponentB             //父组件向子组件通信
            v-for="a in aList"
            v-bind:url="a.url"
            v-bind:title="a.title"
        ></ComponentB>
       <p> 被选了{{num}}次!</p>     <!--子组件向父组件通信-->
        <ComponentC
            v-for="name in nameList"
            v-bind:name="name"
            v-on:do="foo"
        ></ComponentC>
        <table>                 //组件的is属性
        <!-- <ComponentB></ComponentB> 此时组件中template中的tr会显示在table外-->
        <tr is="ComponentB"></tr>  //此时组件中template中的tr会显示在table中的tbody中
        </table>
    </div>
    <script src="./node_modules/vue/dist/vue.js"></script>  <!--通过npm导入vue.js-->
    <script>
        //全局注册组件:定义一个名为button-counter的新组件
        Vue.component('button-counter', {
        /* data: {
            count: 0
            } */
        data: function (){      //data 必须是一个函数,不能直接是对象,组件复用时会影响到其他实例
            return {
                count: 0
            }
        },
        template: '<button v-on:click="count++">你点了我 {{ count }} 次。</button>'
        })
        //局部注册组件:局部注册的组件在其子组件中不可用,如果你希望ComponentB在ComponentA中可用,需声明
        const ComponentA = {
             components: {
                ComponentB
            },
            template: `<a href='https://www.sogo.com'>点我</a>`,
            data: function(){
                return {
                }
            }
        }
        //父组件向子组件通信
        const ComponentB  = {
            //template: `<a> <slot></slot></a>`,通过插槽slot分发内容
            //template: ` <tr><slot></slot></tr>`,组件的is属性
            template: `<p><a v-bind:href='url'>{{title}}</a></p>`,
            props: {            //在子组件中使用props声明将url、title传入组件template并显示
                url: String,     //对传值进行校验
                title: {
                    type: String,
                    required: true
                }
            },
            data: function(){
                return {

                }
            }
        }
         //子组件向父组件通信
        const ComponentC = {
            //子组件可以通过调用内建的 $emit 方法 并传入事件名称来触发一个事件
            template: `<button v-on:click='$emit("do")'>{{ name }}</button>`,
            props: {        //使用props声明将name传入组件template并显示
                name
            },
            methods: {
                do(){
​
                }
            }
        }
        var vm = new Vue({
            el: '#app',
            components:{        //局部注册组件需要在components中声明
                'component-a': ComponentA,
                ComponentB,
                ComponentC
            },
             data: {
                num:0,
                nameList: ["技师A", '技师B', '技师C'],
                aList: [
                    {
                        url: 'https://www.sogo.com',
                        title: 'sogo'
                    },
                    {
                        url: 'https://www.luffycity.com',
                        title: 'luffycity'
                    },
                    {
                        url: 'http://www.oldboyedu.com/',
                        title: 'oldboy edu'
                    },
                ]
            },
            methods: {
                foo(){
                    this.num += 1;
                }
            }
        })
    </script>
</body>
</html>

13.11Vue脚手架开发工具

1. 安装
npm install -g vue-cli
2. 使用
查看安装的vue-cli版本:vue -V
查看帮助:vue --help
查看支持的模板:vue list
3.创建Vue项目
webpack简单模板:vue init webpack-simple app01
webpack模板:(使用Bootstrap时候要用这个):vue init webpack vueapp01
    ? Project name vueapp01                     '回车确认'
    ? Project description A Vue.js project        '回车确认'
    ? Author Lmy <1592187014@qq.com>             '回车确认'
    ? Vue build (Use arrow keys)
    ? Vue build (standalone)
        > Runtime + Compiler: recommended for most users    '回车确认'
        Runtime-only: about 6KB lighter min+gzip, but templates (or any Vue-specific HTML) are              ONLY allowed in .vue files - render functions are required elsewhere
    ? Install vue-router? 'Yes'
    ? Use ESLint to lint your code? 'No'
    ? Set up unit tests No '(设置单元测试)'
    ? Setup e2e tests with Nightwatch?  'No'   '(用夜视器设置e2e测试?)'
    ? Should we run `npm install` for you after the project has been created? (recommended) (Use arrow keys)    '(npm)'
        > Yes, use NPM    '回车确认'
        Yes, use Yarn
        No, I will handle that myself
    。。。。( vue-cli · Generated "vueapp01".)。。。。(Installing project dependencies ...)。。。。 Project initialization finished!。。。。。。
'''To get started:
  cd vueapp01
  npm run dev'''
C:\untitled>cd vueapp01
C:\untitled\vueapp01>npm run dev '(启动前端服务)'' Your application is running here: http://localhost:8080'
停止项目:Ctrl + C
4.在当前项目下安装bootstrap
C:\untitled\vueapp01>npm install bootstrap@3.3.7 -D  或者  npm install bootstrap@3.3.7 --save-d
'安装开发环境下的bootstrap,并将依赖关系写入package.json中'

13.12Vue Router的使用

两个组件(Vue Router内置组件):

<router-link to="/foo">Go to Foo</router-link> #默认渲染成a标签
<router-view></router-view>                  #路由视图,组件显示位置

制作组件路由:

components/Home.vue

<template>
    <div>
        <h1>这是home页面</h1>   //vue文件中,组件template一定要用div包裹所有标签
    </div>
</template>
​
<script>
export default {
    name:'Home',
}
</script>
​
<style>
​
</style>
​

components/Note.vue

<template>
    <div>
        <h1>这是note页面</h1>
    </div>
</template>
​
<script>
export default {
    name:'Note',
}
</script>
​
<style>
</style>

router/index.js

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Home from '@/components/Home.vue'  //从组件导入,@代表src
import Note from '@/components/Note.vue'
​
Vue.use(Router)
​
export default new Router({
  mode:'history',                       //去掉URL中的'#'
  routes: [                             //设置组件路由对应关系
    {
      path: '/home',
      name: '我的home页面',
      component: Home
    },
    {
      path: '/note',
      name: '我的note页面',
      component: Note
    }
  ]
})

Apple.vue:

<li><router-link to="/home">link home版</router-link></li>
<li><router-link to="/note">link note版</router-link></li>
<router-view></router-view>

<router-link
          to="/home"
          tag="li"               #指定生成li标签
          active-class="active"   #指定标签被点击时的样式
        >
          <a href="">link home版</a>
        </router-link>
 <router-link
          to="/note"
          tag="li"
          active-class="active"
        >
          <a href="">link note版</a>
        </router-link>
<router-view></router-view>

<router-link
    v-for="(item,index) in allRouters"
    v-bind:to="item.path"
    tag="li"
    active-class="active"
    v-bind:key=index
        >
    <a href="">{{ item.name }}</a>
</router-link>
<router-view></router-view>
​
<script>
import 'bootstrap/dist/css/bootstrap.min.css'
export default {
  name: 'App',
  // 计算属性
  computed:{
    allRouters(){   // 当前Vue实例注册的所有路由
      return this.$router.options.routes
    }
  }
}
</script>

main.js:

import Vue from 'vue'
import App from './App'
import router from './router'  //导入路由对象
​
Vue.config.productionTip = false
​
/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,           //注册路由对象
  components: { App },
  template: '<App/>'
})

13.13Vuex的使用

store.js:

import Vue from 'vue'
import Vuex from 'vuex'
​
Vue.use(Vuex)
// 开一家商店
export default new Vuex.Store({
    state: {
      count:0
    },
    mutations:{             //提交 mutation来更改 Vuex 的 store 中的状态
      increment(state){
        state.count+=1
      }
    }
  })

main.js:

import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'
​
Vue.config.productionTip = false
​
/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,   //注册路由对象
  store,    //向vue实例注册我的商店
  components: { App },
  template: '<App/>'
})

NoteItem.vue:

<template>
  <div
  class="list-group-item"
  v-on:click="foo"
  >
  {{n}}
  </div>
</template>
​
<script>
export default{
    name:'NoteItem',
    props:{
      n:String
    },
    methods:{                   //v-on监听事件使用method
      foo(){                  //子组件被点击时向父组件传值 ,使用$emit()传递事件,告知父组件子组件被点击
       // this.$emit('plus')   //使用子组件向父组件传值时使用$emit,使用vuex时注释此项
       //this.$store.state.count+=1      //使用vuex,在被点击时修改store中的count
       this.$store.commit('increment')  //使用vuex,在被点击时提交事件increme
    }
    }
  }
</script>
​
<style>
</style>

NoteList.vue:

<template>
    <div>
    <div class="list-group">
      <!-- #父组件向子组件传值,将循环数据使用v-bind传给子组件,子使用props接收并使用,后替换NoteItem -->
            <NoteItem
            v-for="(note,index) in noteList"
            v-bind:n='note'
            v-bind:key='index'
            v-on:plus='p'>  <!-- #子组件向父组件传值,使用v-on监听$emit传递的事件 -->
            </NoteItem>
            <p>计数器:{{count}}</p>
        </div>
     </div>
</template>
​
<script>
  import NoteItem from '@/components/NoteItem'
  export default {
    name:'NoteList',
    components:{
       NoteItem
     },
     data:function() {
       return {
         noteList: [
           '第一项','第二项','第三项'
         ],
         //count:0          //使用子组件向父组件传值时使用data,使用vuex时注释此项
       }
     },
     methods:{     //v-on监听事件使用method
       p(){
         //console.log(this.count);
         this.count+=1
     }
     },
     computed:{         //使用vuex时使用此项,要用return返回
       count:function() {
         return this.$store.state.count
       }
     }
​
}
</script>
<style>
</style>

Vue组件之间的通信:

   父组件->子组件:子组件中要使用:props声明我接收的变量

   子组件 -> 父组件:1.子组件 通过this.$emit('事件名') 向父组件抛出事件

           2.父组件 通过v-on:事件名='方法名' 监听子组件的事件从而触发一个修改数据的方法

13.14使用Django前后端交互

1.django做后端,(先导入pip3 install django-cors-headers)在Django的settings文件中配置:

#允许跨域请求的IP(因为vue默认8080端口,Django默认8000端口)
#授权白名单
CORS_ORIGIN_WHITELIST=(
    'http://localhost:8080',
    'http://127.0.0.1:8080'
)

views.py:

from app01 import models
from django.http import JsonResponse
​
def note_list(request):
    ret = {"code": 0}
    data = list(models.Note.objects.all().values("id", "title", "content", "markedcontent"))
    ret["data"] = data
    return JsonResponse(ret) #返回json字符串

2.vue作前端,使用axios发送请求并接受后端的数据(安装:npm install axios)

App.vue:

<script>
  import 'bootstrap/dist/css/bootstrap.min.css'
  export default {
    name: 'App',
    data: function () {
      return {}
    },
    // 计算属性
    computed: {
      // 当前Vue实例注册的所有路由
      allRouters() {
        return this.$router.options.routes
      }
    },
    beforeMount(){     //在挂载前执行store.js中的playNote函数接受后端数据
     this.$store.commit('playNote')
    },
  }
</script>

store.js:将接收到的数据放进商店

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'  //导入axios
Vue.use(Vuex)
​
export default new Vuex.Store({
    state: {
      count:0,
      notelist:[]
    },
    mutations:{

      addnote_store(state,data){   //捕获NoteEdit传到store的数据用data接收
        state.notelist.push(data)
      },
      playNote(state,data){
        //在挂载DOM之前向后端获取数据
        axios.get('http://127.0.0.1:8000/api/notes/')  //访问note_list视图函数的路由
               .then(function (response) {          //response接收包含json字符串(ret)在内的数据
                   //console.log(response.data.data);
                   state.notelist=response.data.data  //后端返回到response中的数据(ret)以data命名
        })
               .catch(function (error) {              //获取后端数据失败打印错误信息
                  console.log(error);
        });
      }
    },
    actions:{

    //方法一:直接将新添加的数据使用 addnote_store添加到 notelist:[]
      addnode_post(context,data){    //异步操作store
     // 发送 POST 请求
       var data=qs.stringify(data) //发送json类型
       axios({
         method: 'post',
         url: 'http://127.0.0.1:8000/api/add/',
         data: data,
         })
         .then(function (response) {
           console.log('插入数据');
             console.log(response);
             context.commit('addnote_store',response.data.data)  // {id: 3, title: "第三条笔记", content: "", markdownContent: ""}
              //此处只让后端在数据库中添加数据,不添加到notelist:[]
           })
         .catch(function (error) {
             console.log(error);
           })
           },
    }
    })

NoteList.vue:取出商店里的数据,交给template进行渲染

<template>
        <div class="list-group">
            <NoteItem
            v-for="(note,index) in noteList"
            v-bind:n='note'
            v-bind:key='index'
            </NoteItem>
        </div>
</template>
​
<script>
  import NoteItem from '@/components/NoteItem'
  export default {
    name:'NoteList',
    components:{
       NoteItem
     },
     data:function() {
       }
     },
     computed:{         //使用vuex时使用此项
       count:function() {
         return this.$store.state.count
       },
       noteList:function(){    //使用vuex获得store的数据
         return this.$store.state.notelist
       }
     }
}
</script>

NoteItem.vue:

<template>
  <div
  class="list-group-item"
  v-on:click="foo"
  >
  {{n.title}}{{n.content}}
  </div>
</template>
​
<script>
export default{
    name:'NoteItem',
    props:{      //props指定接收父组件传递的数据
      n:Object
    },
    methods:{                 //v-on监听事件使用method
      foo(){                  //子组件被点击时向父组件传值 ,使用$emit()传递事件,告知父组件子组件被点击
       // this.$emit('plus')   //使用子组件向父组件传值时使用$emit,使用vuex时注释此项
       //this.$store.state.count+=1      //使用vuex,在被点击时修改store中的count
       this.$store.commit('increment')   //使用vuex,在被点击时提交事件increme
    }
    }
  }
</script>
(0)

相关推荐