use*_*827 18 html javascript django vue.js
我最近开始使用Django在一些社交媒体网站上.我使用默认的django模板引擎来填充我的页面.但此时此刻,我想添加javascript以使网站更具活力.这意味着:
我想用Vue来处理动态组件,但我不知道应该如何开始.申请不应该是SPA.
{% url 'index' %}
在下拉菜单中使用.Man*_*ani 20
这看起来像一个基于意见的问题,没有明确的答案.
您提到您不希望该应用程序成为单页应用程序(SPA).如果是这样,使用Vue的动机是什么?处理页面内的用户交互?
Vue可以在非SPA环境中完美地工作.它将帮助您处理页面中的丰富交互,例如将数据绑定到下拉菜单,表单等.但是当您在SPA上下文中使用Vue时,Vue的真正力量就会出现.
对于您的情况,我建议在独立模式下使用Vue.js ,您可以template
在Vue组件中快速定义并在一个javascript文件中轻松编写所有代码.
您需要的是:https://vuejs.org/guide/installation.html#Standalone
在"Vue.js独立模式"中,不需要任何webpack构建系统或vue-cli
.您可以直接在django的现有开发环境中构建应用程序.gulp
可以选择正常缩小和捆绑您的javascript文件,就像使用基于jQuery的应用程序一样.
Vue.js使用双花括号{{..}}
作为模板,因此它不会干扰你的django模板字符串.
Vue.js的所有jsFiddle示例都以独立模式运行.这正是您目前所需要的.您可以使用vue.js
标签查看一些最近的问题,找到一个示例jsFiddle,看看它是如何完成的.
对于复杂的SPA应用程序,您需要从服务器端单独构建Vue代码,使用虚拟AJAX调用对其进行彻底测试,将其构建用于生产,然后将最终生产版本放入服务器以进行端到端测试.这是你将来可以做的事情.
JL *_*ret 18
我一会儿看着这个问题和其他人,同时他们正在寻找OP所要求的内容.不幸的是,关于Vue的大多数信息都是在SPA环境中给出的.但是,正如Evan You经常重复的那样,Vue并不是固执己见的,也不需要在SPA中使用.
我想分享一些我的发现,并勾勒出让Django和Vue一起工作的可能方法.虽然不需要SPA,但我认为Vue的真正功能来自于它的组件,这有点推动您使用Webpack或类似的方法,而不是html中的简单独立模式.
另外,要非常清楚:我的内容的90%以上Django视图代码和模板与以前完全相同.Django并不特别在意它正在使用webpack_loader和render_bundle.甚至更少的render_bundle与Vue有关.在Django template blocks
,verbatim
标签和Vue之间slots
,您可以获得很多灵活性,使您可以单独留下大部分现有内容.
最后,一旦你的应用程序稳定,你可以在端口3000上禁用hotreload服务器,运行npm run build-production
并使用collectstatic
通过nginx/apache提供你的JS,就像任何正常的静态内容一样.因此node
,偶尔运行而不是作为服务运行.需要稍微摆弄Django的配置,但在合理范围内.
道歉,这是非常粗略的,不要指望工作代码,因为我剥离了这么多.但希望它会给你一个想法.
mysite的/ __ full12_vue.html:
这是我的基础Vue-ify Django模板,它扩展了我现有的Django基础模板__full12.html.
假设__full12.html定义了所有常规Django块,例如{%block content%}等
(实际上,有一个非常重要的div,ID bme-vue
所以我也在最后添加了这个模板.)
我添加了一个Vue组件来显示用户消息.
并重新定义了菜单模板以使用Vue + Bootstrap下拉菜单.
{% extends "mysite/__full12.html" %}
<!-- KEY: use this to hook up to https://github.com/ezhome/django-webpack-loader -->
{% load render_bundle from webpack_loader %}
{% block nav %}
<!-- uses Vue to setup Bootstrap dropdown menus -->
{% include "mysite/menu_vue.html" %}
{% endblock nav %}
{% block user_msg %}
<div class="row">
<div class="col-6">
<!-- uses Vue to display user messages -->
<bme-user-messages>
<div>THIS SHOULDNT APPEAR ON SCREEN IF VUE WORKED</div>
</bme-user-messages>
</div>
</div>
{% endblock user_msg %}
{%block extra_js_body_end%}
<!-- KEY this points Django Webpack loader to appropriate Webpack entry point -->
{% render_bundle bundle_name %}
{%endblock extra_js_body_end%}
Run Code Online (Sandbox Code Playgroud)
webpack.config.development.js:
这是您告诉Webpack哪个JS为您在视图中指定的bundle_name提供服务的地方.
如何配置Webpack超出了我的职位范围,但我可以向你保证这是一个真正的PIA.我开始使用pip django-webpack-loader,然后https://github.com/NdagiStanley/vue-django然后启动Bootstrap 4.但是,在我看来,最终结果比独立更强大.
/*
webpack config dev for retest
*/
config.entry = {
"main" : [
'webpack-dev-server/client?http://localhost:3000','../../static_src/js/index'],
// ....stuff..
//KEY: ONE entrypoint for EACH bundlename that you use.
"mydjangoappname/some_django_view" : ["../../static_src/js/mydjangoappname/some_django_view"],
"mydjangoappname/another_django_view" : ["../../static_src/js/mydjangoappname/another_django_view"],
// ....stuff..
}
// ....stuff left out...
Run Code Online (Sandbox Code Playgroud)
mydjangoappname/some_django_template.html
最后,我们准备显示一些实际内容:
bme-nav-item
并且bme-tab-pane
是我用于Boostrap 4选项卡导航和内容的2个自定义Vue组件.
Django用于var settings= some-json-object
将特定于实例的数据而非页面通用数据传递给Vue和JS
{% extends "mysite/__full12_vue.html" %}
<script>
// KEY: settings is provided by json.dumps(some_settings_dictionary)
// which your views puts into your RequestContext.
// this is how Django tells Vue what changes with different data, on the same view
var settings = {{settings | safe}};
</script>
{% block content %}
<!-- a button to run a Celery batch via a post command, url should probably come
from Django url reverse and be put into a Vue property...
-->
<button v-bind:data-url="url_batch" type="button" class="btn btn-block btn-outline-primary" @click.prevent="run_batch">
<!-- lotsa stuff left out.... -->
<ul id="tab-contents-nav" class="nav nav-tabs nav-pills">
<!-- *label* is using a Vue Prop and because there is no {% verbatim %} guard around it, Django will
inject the contents. {% urlrev xxx %} could be used to write to an 'url' prop. Ditto the conditional
inclusion, by Django, of a template if it's in the RequestContext.
-->
{% if templatename_details %}
<bme-nav-item link="details"
label="{{details_label}}" >
</bme-nav-item>
{% endif %}
<!-- lotsa stuff left out.... -->
<bme-tab-pane link="details">
<div slot="content">
<!-- KEY: Vue slots are incredibly powerful with Django. Basically this is saying
to Django : inject what you want in the slot, using your include, I'll tidy up afterwards.
In my case, this is a Bootstrap NavItem + NavTab
-->
{% if templatename_details %}
{% include templatename_details %}
{% else %}
<span class="text-warning">SHOULDNT APPEAR IF VUE WORKED </span>
{% endif %}
</div>
</bme-tab-pane>
{% endblock content %}
Run Code Online (Sandbox Code Playgroud)
mydjangoappname/some_django_view.js:
import Vue from 'vue';
import Vuex from 'vuex';
//now Vue is using Vuex, which injects $store centralized state variables as needed
Vue.use(Vuex);
//KEY: re-using components defined once.
import {base_messages, base_components} from '../mysite/commonbase.js';
var local_components = {
//nothing, but I could have imported some other components to mix-n-match
//in any case, bme-nav-item, bme-tab-pane and bme-user-messages need to
//coming from somewhere for this page!
};
const components = Object.assign({}, base_components, local_components);
//we're going to put together a Vue on the fly...
export function dovue(config) {
//KEY: The store is a Vuex object - don't be fooled, it's not SPA-only
// it's the easiest way to coherently share data across Vue Components, so use it.
store.commit('initialize', config);
//here I am telling the store which html IDs need hiding
var li_tohide = settings.li_tohide || [];
li_tohide.forEach(function(hidden) {
store.commit('add_hidden', hidden);
});
/* eslint-disable no-new */
var vm = new Vue({
//KEY: This tells the Vue instance what parts of your html are in its scope.
el: '#bme-vue'
//KEY: each bme-xxx and bme-yyy special tag needs to be found in components below
//otherwise you'll see my SHOULDNT APPEAR IF VUE WORKED text in your page
,components: components
,data: {
li_rowcount: window.settings.li_rowcount || []
,csrf_token: window.csrf_token
,url_batch: "some url"
}
,mounted: function () {
// a Vue lifecycle hook. You could use to set up Vue Event listening for example
console.log("data.js.lifecycle.mounted");
}
,methods : {
,run_batch: function(e) {
//hook this up to a button
console.assert(this.$data, COMPONENTNAME + ".run_batch.this.$data missing. check object types");
var url = e.target.dataset.url
//this is defined elsewhere
post_url_message(this, url, this.csrf_token);
}
}
//the Vuex instance to use for this Vue.
,store: store
});
//did Django provide any user messages that need displaying?
var li_user_message = config.li_user_message || [];
li_user_message.forEach(function(user_message, i) {
//the bme-user-messages Component? It's listening for this event
//and will display Bootstrap Alerts for them.
vm.$emit(base_messages.EV_USER_MESSAGE, user_message);
});
return vm;
}
//various app and page specific settings...
import {app_config, LOCALNAV_LINK, TOPNAV_LINK_OTHERS} from "./constants";
var page_config = {
//used to show which navigation items are .active
localnav_link : LOCALNAV_LINK.data
, topnav_link: TOPNAV_LINK_OTHERS.system_edit_currentdb
};
//this is coming from Django's RequestContext.
var generated_config = window.settings;
//ok, now we are merging together a Django app level config, the page config and finally
//what the Django view has put into settings. This will be passed to the Vuex store
//individual Vue Components will then grab what they need from their $store attribute
//which will point to that Vuex instance.
var local_config = Object.assign({}, app_config, page_config, generated_config);
var vm = dovue(local_config);
Run Code Online (Sandbox Code Playgroud)
vuex/generic.js:
还有一个天真的,大多数只读的商店实现:
//you can add your page's extra state, but this is a shared baseline
//for the site
const state = {
active_tab: ""
,topnav_link: ""
,localnav_link: ""
,li_user_message: []
,s_visible_tabid: new Set()
,urls: {}
};
const mutations = {
//this is what your page-specific JS is putting into the state.
initialize(state, config){
//initialize the store to a given configuration
//KEY: attributes that did not exist on the state in the first place wont be reactive.
// console.log("store.initialize");
Object.assign(state, config);
},
//a sample mutation
set_active_tab(state, tabid){
//which bme-tab-nav is active?
if (! state.s_visible_tab.has(tabid)){
return;
}
state.active_tab = tabid;
},
};
export {state as generic_state, mutations};
Run Code Online (Sandbox Code Playgroud)
并让您了解一般文件层次结构:
.
./manage.py
./package.json //keep this under version control
./
??? mydjangoappname
? ??? migrations
? ??? static
? ??? mydjangoappname
??? node_modules
? //lots of JavaScript packages here, deposited/managed via npm && package.json
??? static
? ??? js
??? static_src
? ??? assets
? ??? bundles
? ? // this is where django-webpack-loader's default config deposits generated bundles...
? ? // probably belonged somewhere else than under static_src ...
? ? ??? mydjangoappname
? ??? components
? ? ??? mydjangoappname
? ??? css
? ??? js
? ? ??? mydjangoappname
? ? ??? mysite
? ??? vuex
? ??? mydjangoappname
??? staticfiles
? // for Production, collectstatic should grab django-webpack-loader's bundles, I think...
??? templates
? ??? admin
? ? ??? pssystem
? ??? mydjangoappname
? ??? mysite
??? mysite
??? config
? // where you configure webpack and the entry points.
? webpack.config.development.js
??? sql
? ??? sysdata
??? static
? ??? mysite
??? templatetags
Run Code Online (Sandbox Code Playgroud)
好的,我必须修改网站的基本模板,以确保div#bme-vue始终可用.
可能需要在这个和mysite/__ full12_vue.html之间进行一些重构.
mysite/__ full12.html:
<!-- lots of stuff left out -->
<body>
<!-- KEY: the #bme-vue wrapper/css selector tells Vue what's in scope.
it needs to span as much of the <body> as possible, but
also end right BEFORE the render_bundle tag. I set that css
selector in mydjangoappname/some_django_view.js and I'd want to
use the same selector everywhere throughout my app.
-->
<div id="bme-vue">
<!-- anything that ends up here
, including through multiple nested/overridden Django content blocks
, can be processed by Vue
, but only when have Vue-relevant markup
such as custom component tags or v-for directives.
-->
...more blocks...
{% block search %}
{% endblock search %}
<div id="main" role="main">
<div> <!-- class="container"> -->
{% block content %}
{% endblock %}
</div>
</div>
...more blocks...
</div> <!-- bme-vue -->
{%block extra_js_body_end%}
{%endblock extra_js_body_end%}
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
20962 次 |
最近记录: |